home *** CD-ROM | disk | FTP | other *** search
/ Aminet 12 / Aminet 12 (1996)(GTI - Schatztruhe)[!][Jun 1996].iso / Aminet / gfx / show / gs_src_amiga.lha / gdevamiga.c < prev    next >
C/C++ Source or Header  |  1996-03-18  |  112KB  |  5,370 lines

  1. /* Copyright (C) 1992, 1995 Aladdin Enterprises.  All rights reserved.
  2.  
  3.   This file is part of Aladdin Ghostscript.
  4.  
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.  
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevamiga.c */
  20. /* Amiga driver for Ghostscript library, requires Kickstart 2.04 or higher */
  21.  
  22. /* Written by Olaf `Olsen' Barthel, last change 9 October 1995
  23.  *
  24.  * My address:   Olaf Barthel
  25.  *               Brabeckstrasse 35
  26.  *             D-30559 Hannover
  27.  *
  28.  *      eMail:   olsen@sourcery.han.de
  29.  */
  30.  
  31. #define CheckIO foo123
  32. #define ushort foo
  33.  
  34. #include <intuition/intuitionbase.h>
  35. #include <intuition/gadgetclass.h>
  36. #include <intuition/imageclass.h>
  37. #include <intuition/icclass.h>
  38. #include <graphics/displayinfo.h>
  39. #include <libraries/iffparse.h>
  40. #include <graphics/gfxbase.h>
  41. #include <devices/printer.h>
  42. #include <devices/prtbase.h>
  43. #include <devices/prtgfx.h>
  44. #include <libraries/asl.h>
  45. #include <exec/memory.h>
  46. #include <clib/macros.h>
  47. #include <dos/dostags.h>
  48. #include <dos/rdargs.h>
  49. #include <dos/var.h>
  50. #include <dos/dos.h>
  51.  
  52. #include <proto/intuition.h>
  53.  
  54. #define BltBitMap BlitBitMap
  55. #include <proto/graphics.h>
  56. #undef BltBitMap
  57.  
  58. #include <proto/iffparse.h>
  59. #include <proto/utility.h>
  60. #include <proto/layers.h>
  61. #include <proto/exec.h>
  62. #include <proto/dos.h>
  63. #include <proto/asl.h>
  64.  
  65. /*
  66. #include <inline/stubs.h>
  67. #include <inline/iffparse.h>
  68. #include <inline/utility.h>
  69. #include <inline/exec.h>
  70. #include <inline/dos.h>
  71. */
  72.  
  73. #include <string.h>
  74. #include <signal.h>
  75.  
  76. #undef ushort
  77. #undef CheckIO
  78.  
  79. struct IORequest *CheckIO(struct IORequest *);
  80.  
  81. #include "gx.h"        /* for gx_bitmap; includes std.h */
  82. #include "gsmatrix.h"    /* needed for gxdevice.h */
  83. #include "gxdevice.h"
  84. #include "gserrors.h"
  85. /*#include "gsprops.h"*/
  86.  
  87. #ifdef m68030
  88. #ifdef m68881
  89. STATIC STRPTR VersTag = "$VER: gs 3.53 (9.10.95) MC68030/FPU version\r\n";
  90. #else
  91. STATIC STRPTR VersTag = "$VER: gs 3.53 (9.10.95) MC68030 version\r\n";
  92. #endif    /* m68881 */
  93. #else
  94. STATIC STRPTR VersTag = "$VER: gs 3.53 (9.10.95)\r\n";
  95. #endif    /* mc68030 */
  96.  
  97.     /* Here is how to select a default page size format:
  98.      *
  99.      * Either enter include a line such as
  100.      *
  101.      *   #define AMIGA_PAGE_A4 1
  102.      *
  103.      * Somewhere above in this module, or edit the makefile
  104.      * to feature the option
  105.      *
  106.      *   -dAMIGA_PAGE_A4
  107.      *
  108.      * among the device specific flags. Available default page
  109.      * size formats are:
  110.      *
  111.      *   AMIGA_PAGE_A4         European A4 page size (default)
  112.      *   AMIGA_PAGE_A3         European A3 page size
  113.      *   AMIGA_PAGE_LETTER     US letter page size
  114.      *   AMIGA_PAGE_LEGAL      US legal page size
  115.      *   AMIGA_PAGE_LEDGER     US ledger paper size
  116.      *   AMIGA_PAGE_TABLOID    US tabloid paper size
  117.      */
  118.  
  119.     /* Select the default paper size if none specified. */
  120.  
  121. #if !defined(AMIGA_PAGE_A4) && !defined(AMIGA_PAGE_A3) && !defined(AMIGA_PAGE_LETTER) && !defined(AMIGA_PAGE_LEGAL) && !defined(AMIGA_PAGE_LEDGER) && !defined(AMIGA_PAGE_TABLOID)
  122. #define AMIGA_PAGE_A4 1
  123. /*#define AMIGA_PAGE_A3 1*/
  124. #endif    /* PAGE SIZE */
  125.  
  126.     /* A4 page size (in inches!) */
  127.  
  128. #ifdef AMIGA_PAGE_A4
  129. #define DEFAULT_WIDTH        8.2
  130. #define DEFAULT_HEIGHT        11.6
  131. #endif    /* AMIGA_PAGE_A4 */
  132.  
  133.     /* A3 page size */
  134.  
  135. #ifdef AMIGA_PAGE_A3
  136. #define DEFAULT_WIDTH        11.6
  137. #define DEFAULT_HEIGHT        16.5
  138. #endif    /* AMIGA_PAGE_A4 */
  139.  
  140.     /* US letter page size */
  141.  
  142. #ifdef AMIGA_PAGE_LETTER
  143. #define DEFAULT_WIDTH        8.5
  144. #define DEFAULT_HEIGHT        11.0
  145. #endif    /* AMIGA_PAGE_LETTER */
  146.  
  147.     /* US legal page size */
  148.  
  149. #ifdef AMIGA_PAGE_LEGAL
  150. #define DEFAULT_WIDTH        8.5
  151. #define DEFAULT_HEIGHT        14.0
  152. #endif    /* AMIGA_PAGE_LEGAL */
  153.  
  154.     /* US ledger page size */
  155.  
  156. #ifdef AMIGA_PAGE_LEDGER
  157. #define DEFAULT_WIDTH        16.0
  158. #define DEFAULT_HEIGHT        11.0
  159. #endif    /* AMIGA_PAGE_LEDGER */
  160.  
  161.     /* US tabloid page size */
  162.  
  163. #ifdef AMIGA_PAGE_TABLOID
  164. #define DEFAULT_WIDTH        11.0
  165. #define DEFAULT_HEIGHT        17.0
  166. #endif    /* AMIGA_PAGE_LEDGER */
  167.  
  168.     /* Default output file name. */
  169.  
  170. #define DEFAULT_FILENAME    "gs_page"
  171.  
  172.     /* Turn a byte into a 24 bit colour value. */
  173.  
  174. #define SPREAD(i)    ((ULONG)(i) << 24 | (ULONG)(i) << 16 | (ULONG)(i) << 8 | (i))
  175.  
  176.     /* Scroller gadget IDs. */
  177.  
  178. enum    {    VERTICAL_SCROLLER,    HORIZONTAL_SCROLLER,
  179.         UP_ARROW,        DOWN_ARROW,
  180.         LEFT_ARROW,        RIGHT_ARROW,
  181.  
  182.         GADGET_COUNT
  183.     };
  184.  
  185.     /* Scroller arrow IDs. */
  186.  
  187. enum    {    UP_IMAGE,        DOWN_IMAGE,
  188.         LEFT_IMAGE,        RIGHT_IMAGE,
  189.  
  190.         IMAGE_COUNT
  191.     };
  192.  
  193.     /* Codes for the MoveAround() routine. */
  194.  
  195. enum    {    MOVE_MIN,MOVE_FAR_DOWN,MOVE_DOWN,MOVE_UP,MOVE_FAR_UP,MOVE_MAX };
  196.  
  197.     /* Some handy bit masks. */
  198.  
  199. #define SIG_KILL    SIGBREAKF_CTRL_C
  200. #define SIG_HANDSHAKE    SIGF_SINGLE
  201. #define SIG_WAKEUP    SIGBREAKF_CTRL_E
  202.  
  203.     /* Static dimensions of scroller arrows. */
  204.  
  205. #define ARROW_WIDTH    16
  206. #define ARROW_HEIGHT    11
  207.  
  208.     /* The `Help' key raw code. */
  209.  
  210. #define HELP_CODE    95
  211.  
  212.     /* Minimum window inner area dimension. */
  213.  
  214. #define MINIMUM_WIDTH    64
  215. #define MINIMUM_HEIGHT    32
  216.  
  217.     /* Handy superbitmap window macros. */
  218.  
  219. #define LAYERXOFFSET(w)    ((w) -> RPort -> Layer -> Scroll_X)
  220. #define LAYERYOFFSET(w)    ((w) -> RPort -> Layer -> Scroll_Y)
  221.  
  222.     /* User input to listen to. */
  223.  
  224. #define IDCMP_FLAGS    (IDCMP_IDCMPUPDATE | IDCMP_GADGETUP | IDCMP_GADGETDOWN | IDCMP_MOUSEMOVE | IDCMP_NEWSIZE | IDCMP_CLOSEWINDOW | IDCMP_VANILLAKEY | IDCMP_RAWKEY)
  225.  
  226.     /* Chunk IDs. */
  227.  
  228. #define ID_ILBM        MAKE_ID('I','L','B','M')
  229. #define ID_BMHD        MAKE_ID('B','M','H','D')
  230. #define ID_CMAP        MAKE_ID('C','M','A','P')
  231. #define ID_CAMG        MAKE_ID('C','A','M','G')
  232. #define ID_ANNO        MAKE_ID('A','N','N','O')
  233. #define ID_DPI        MAKE_ID('D','P','I',' ')
  234. #define ID_BODY        MAKE_ID('B','O','D','Y')
  235.  
  236.     /* Chunk contents definitions. */
  237.  
  238. typedef struct
  239. {
  240.     UWORD        w,h;            /* raster width & height in pixels */
  241.     WORD        x,y;            /* position for this image */
  242.     UBYTE        nPlanes;        /* # source bitplanes */
  243.     UBYTE        masking;        /* masking technique */
  244.     UBYTE        compression;        /* compression algoithm */
  245.     UBYTE        pad1;            /* UNUSED.  For consistency, put 0 here.*/
  246.     UWORD        transparentColor;    /* transparent "color number" */
  247.     UBYTE        xAspect,yAspect;    /* aspect ratio, a rational number x/y */
  248.     WORD        pageWidth,pageHeight;    /* source "page" size in pixels */
  249. } BitMapHeader;
  250.  
  251. typedef struct
  252. {
  253.     UWORD        dpi_x;
  254.     UWORD        dpi_y;
  255. } DPIHeader;
  256.  
  257.     /* Packer modes. */
  258.  
  259. #define DUMP        0
  260. #define RUN        1
  261.  
  262.     /* Minimum data run size, maximum data run size and maximum cache size. */
  263.  
  264. #define MINRUN        3
  265. #define MAXRUN        128
  266. #define MAXDAT        128
  267.  
  268.     /* This module actually implements four different Amiga based
  269.      * devices. As the rendering operations are all the same,
  270.      * one single device definition is sufficient.
  271.      */
  272.  
  273. typedef struct gx_device_amiga
  274. {
  275.     gx_device_common;
  276.  
  277.     struct Screen    *screen;    /* Any screen */
  278.     struct Window    *window;    /* Some window to be opened on the Workbench screen */
  279.  
  280.     LONG         super_width,    /* Superbitmap width */
  281.              super_height;    /* Superbitmap height */
  282.  
  283.     struct BitMap    *super_bitmap;    /* Window superbitmap area */
  284.     struct Gadget    **gadget;    /* Scroller gadgets */
  285.     struct Image    **image;    /* Scroller arrow images */
  286.  
  287.     struct Task    *dispatcher;    /* Slider dispatch task */
  288.     struct Process    *main;        /* Main program */
  289.  
  290.     struct RastPort    *rport;        /* Rendering area */
  291.  
  292.     struct IODRPReq *printer;    /* Printer interface data */
  293.     struct MsgPort    *port;        /* Printer io data */
  294.  
  295.     struct ColorMap    *colormap;    /* A black/white colour map */
  296.     struct BitMap    *bitmap;    /* Rendering bitmap data */
  297.     PLANEPTR     bitplane;    /* Rendering raster */
  298.  
  299.     gx_color_index     last_pen;    /* The last colour set */
  300.  
  301.     double         page_width,    /* The page width */
  302.              page_height;    /* The page height */
  303.     char         file_name[256];/* The output file name */
  304.     int         page_count;    /* The page number counter */
  305.  
  306.     int         cube_size;    /* Colour cube size, 0 for b/w */
  307.     struct RastPort    *temp_rport;    /* Temporary raster port for pixmap imaging. */
  308.     UBYTE        *temp_array;    /* Temporary colour manipulation array. */
  309.     LONG        *pens;
  310. } gx_device_amiga;
  311.  
  312.     /* Function prototypes */
  313.  
  314. VOID            set_mono_device(gx_device_amiga *dev);
  315. VOID            set_colour_device(gx_device_amiga *dev,int cube_size,LONG *pens);
  316. VOID            set_colour_printer_device(gx_device_amiga *dev,LONG CubeSize);
  317. VOID            DeleteBitMap(struct BitMap *BitMap,BOOL Private);
  318. struct BitMap *        CreateBitMap(LONG Width,LONG Height,LONG Depth,ULONG Flags,struct BitMap *Friend,BOOL Private);
  319. VOID            DeleteTempRPort(struct RastPort *Temp);
  320. struct RastPort *    CreateTempRPort(struct RastPort *Source);
  321. LONG            Euclid(LONG a,LONG b);
  322. BYTE *            PutDump(register BYTE *Destination,register LONG Count);
  323. BYTE *            PutRun(register BYTE *Destination,LONG Count,WORD Char);
  324. LONG            PackRow(PLANEPTR *SourcePtr,register BYTE *Destination,LONG RowSize);
  325. BOOL            PutBODY(struct IFFHandle *Handle,struct BitMap *BitMap);
  326. BOOL            PutANNO(struct IFFHandle *Handle);
  327. BOOL            PutCAMG(struct IFFHandle *Handle);
  328. BOOL            PutCMAP(struct IFFHandle *Handle);
  329. BOOL            PutDPI(struct IFFHandle *Handle,UWORD X_DPI,UWORD Y_DPI);
  330. BOOL            PutBMHD(struct IFFHandle *Handle,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI);
  331. BOOL            SaveBitMap(STRPTR Name,struct BitMap *BitMap,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI);
  332. double            GetInches(STRPTR Buffer);
  333. VOID            DispatchTask(VOID);
  334. VOID            DeleteScrollers(gx_device *dev);
  335. BOOL            CreateScrollers(gx_device *dev,struct Screen *Screen);
  336. VOID            WindowResize(gx_device *dev);
  337. VOID            WindowUpdate(struct Gadget *Gadget,gx_device *dev);
  338. VOID            MoveAround(struct Gadget *Gadget,LONG How,gx_device *dev);
  339. VOID            DispatchSuperWindow(gx_device *dev);
  340. void            devcleanup(VOID);
  341. gx_color_index        amiga_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue);
  342. int            amiga_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3]);
  343. LONG *            AllocatePens(struct ViewPort *VPort,LONG CubeSize);
  344. int            amiga_open_default(gx_device *dev);
  345. int            amiga_open_low(gx_device *dev);
  346. int            amiga_open_high(gx_device *dev);
  347. int            amiga_open_super(gx_device *dev);
  348. int            amiga_open_a2024(gx_device *dev);
  349. int            amiga_open_picassoii(gx_device *dev);
  350. int            amiga_open_custom(gx_device *dev);
  351. int            amiga_open_printer(gx_device *dev);
  352. int            amiga_output_page_printer(gx_device *dev,int num_copies,int flush);
  353. int            amiga_close_printer(gx_device *dev);
  354. int            amiga_open(gx_device *dev,ULONG Mode);
  355. int            amiga_output_page(gx_device *dev,int num_copies,int flush);
  356. int            amiga_close(gx_device *dev);
  357. int            amiga_fill_rectangle(gx_device *dev,int x,int y,int w,int h,gx_color_index color);
  358. int            amiga_copy_mono(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one);
  359. int            amiga_copy_color(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h);
  360. int            amiga_draw_line(gx_device *dev,int x0,int y0,int x1,int y1,gx_color_index color);
  361. int            amiga_copy_mono_raw(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one);
  362. int            amiga_copy_color_raw(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h);
  363. int            amiga_fill_rectangle_raw(gx_device *dev,int x,int y,int w,int h,gx_color_index color);
  364. int            amiga_draw_line_raw(gx_device *dev,int x,int y,int x1,int y1,gx_color_index color);
  365. int            amiga_open_ilbm(gx_device *dev);
  366. int            amiga_output_page_ilbm(gx_device *dev,int num_copies,int flush);
  367. int            amiga_close_ilbm(gx_device *dev);
  368. gx_color_index        amiga_color_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue);
  369. int            amiga_color_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3]);
  370. gx_color_index        amiga_color_map_rgb_color_pen(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue);
  371. int            amiga_color_map_color_rgb_pen(gx_device *dev,gx_color_index color,gx_color_value rgb[3]);
  372. int            amiga_copy_color8(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h);
  373. int            amiga_copy_mono_raw_color(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one);
  374. int            amiga_copy_color_raw_color16(gx_device *dev,const UBYTE *data,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h);
  375. int            amiga_fill_rectangle_raw_color(gx_device *dev,int x,int y,int w,int h,gx_color_index color);
  376. int            amiga_draw_line_raw_color(gx_device *dev,int x,int y,int x1,int y1,gx_color_index color);
  377.  
  378.     /* External reference to some libraries, required for version checking, etc. */
  379.  
  380. extern struct GfxBase *GfxBase;
  381. extern struct Library *AslBase;
  382.  
  383.     /* Number of packed bytes and pack buffer. */
  384.  
  385. LONG    PackedBytes;
  386. BYTE    Buffer[MAXDAT + 1];
  387.  
  388.     /* Bit masks. */
  389.  
  390. STATIC UBYTE    shift[8] = { 128, 64, 32, 16,  8,  4,  2,  1 },
  391.         masks[8] = { 127,191,223,239,247,251,253,254 };
  392.  
  393.     /* Device routine jump tables */
  394.  
  395. STATIC gx_device_procs amiga_default_procs =
  396. {
  397.     amiga_open_default,
  398.     NULL,            /* get_initial_matrix */
  399.     NULL,            /* sync_output */
  400.     amiga_output_page,
  401.     amiga_close,
  402.     amiga_map_rgb_color,
  403.     amiga_map_color_rgb,
  404.     amiga_fill_rectangle,
  405.     NULL,            /* tile_rectangle */
  406.     amiga_copy_mono,
  407.     amiga_copy_color,
  408.     amiga_draw_line,
  409.     NULL,            /* get_bits */
  410.     NULL,            /* get_params */
  411.     NULL,            /* put_params */
  412.     NULL,            /* map_cmyk_color */
  413.     NULL,            /* get_xfont_procs */
  414.     NULL,            /* get_xfont_device */
  415.     NULL,            /* map_rgb_alpha_color */
  416.     NULL,            /* get_page_device */
  417.     NULL,            /* get_alpha_bits */
  418.     NULL,            /* copy_alpha */
  419. };
  420.  
  421. STATIC gx_device_procs amiga_low_procs =
  422. {
  423.     amiga_open_low,
  424.     NULL,
  425.     NULL,
  426.     amiga_output_page,
  427.     amiga_close,
  428.     amiga_map_rgb_color,
  429.     amiga_map_color_rgb,
  430.     amiga_fill_rectangle,
  431.     NULL,
  432.     amiga_copy_mono,
  433.     amiga_copy_color,
  434.     amiga_draw_line,
  435.     NULL,
  436.     NULL,
  437.     NULL,
  438.     NULL,
  439.     NULL,
  440.     NULL,
  441.     NULL,
  442.     NULL,
  443.     NULL,
  444.     NULL,
  445. };
  446.  
  447. STATIC gx_device_procs amiga_high_procs =
  448. {
  449.     amiga_open_high,
  450.     NULL,
  451.     NULL,
  452.     amiga_output_page,
  453.     amiga_close,
  454.     amiga_map_rgb_color,
  455.     amiga_map_color_rgb,
  456.     amiga_fill_rectangle,
  457.     NULL,
  458.     amiga_copy_mono,
  459.     amiga_copy_color,
  460.     amiga_draw_line,
  461.     NULL,
  462.     NULL,
  463.     NULL,
  464.     NULL,
  465.     NULL,
  466.     NULL,
  467.     NULL,
  468.     NULL,
  469.     NULL,
  470.     NULL,
  471. };
  472.  
  473. STATIC gx_device_procs amiga_super_procs =
  474. {
  475.     amiga_open_super,
  476.     NULL,
  477.     NULL,
  478.     amiga_output_page,
  479.     amiga_close,
  480.     amiga_map_rgb_color,
  481.     amiga_map_color_rgb,
  482.     amiga_fill_rectangle,
  483.     NULL,
  484.     amiga_copy_mono,
  485.     amiga_copy_color,
  486.     amiga_draw_line,
  487.     NULL,
  488.     NULL,
  489.     NULL,
  490.     NULL,
  491.     NULL,
  492.     NULL,
  493.     NULL,
  494.     NULL,
  495.     NULL,
  496.     NULL,
  497. };
  498.  
  499. STATIC gx_device_procs amiga_a2024_procs =
  500. {
  501.     amiga_open_a2024,
  502.     NULL,
  503.     NULL,
  504.     amiga_output_page,
  505.     amiga_close,
  506.     amiga_map_rgb_color,
  507.     amiga_map_color_rgb,
  508.     amiga_fill_rectangle,
  509.     NULL,
  510.     amiga_copy_mono,
  511.     amiga_copy_color,
  512.     amiga_draw_line,
  513.     NULL,
  514.     NULL,
  515.     NULL,
  516.     NULL,
  517.     NULL,
  518.     NULL,
  519.     NULL,
  520.     NULL,
  521.     NULL,
  522.     NULL,
  523. };
  524.  
  525. STATIC gx_device_procs amiga_picassoii_procs =
  526. {
  527.     amiga_open_picassoii,
  528.     NULL,
  529.     NULL,
  530.     amiga_output_page,
  531.     amiga_close,
  532.     amiga_map_rgb_color,
  533.     amiga_map_color_rgb,
  534.     amiga_fill_rectangle,
  535.     NULL,
  536.     amiga_copy_mono,
  537.     amiga_copy_color,
  538.     amiga_draw_line,
  539.     NULL,
  540.     NULL,
  541.     NULL,
  542.     NULL,
  543.     NULL,
  544.     NULL,
  545.     NULL,
  546.     NULL,
  547.     NULL,
  548.     NULL,
  549. };
  550.  
  551. STATIC gx_device_procs amiga_custom_procs =
  552. {
  553.     amiga_open_custom,
  554.     NULL,
  555.     NULL,
  556.     amiga_output_page,
  557.     amiga_close,
  558.     amiga_map_rgb_color,
  559.     amiga_map_color_rgb,
  560.     amiga_fill_rectangle,
  561.     NULL,
  562.     amiga_copy_mono,
  563.     amiga_copy_color,
  564.     amiga_draw_line,
  565.     NULL,
  566.     NULL,
  567.     NULL,
  568.     NULL,
  569.     NULL,
  570.     NULL,
  571.     NULL,
  572.     NULL,
  573.     NULL,
  574.     NULL,
  575. };
  576.  
  577. STATIC gx_device_procs amiga_printer_procs =
  578. {
  579.     amiga_open_printer,
  580.     NULL,
  581.     NULL,
  582.     amiga_output_page_printer,
  583.     amiga_close_printer,
  584.     amiga_map_rgb_color,
  585.     amiga_map_color_rgb,
  586.     amiga_fill_rectangle_raw,
  587.     NULL,
  588.     amiga_copy_mono_raw,
  589.     amiga_copy_color_raw,
  590.     amiga_draw_line_raw,
  591.     NULL,
  592.     NULL,
  593.     NULL,
  594.     NULL,
  595.     NULL,
  596.     NULL,
  597.     NULL,
  598.     NULL,
  599.     NULL,
  600.     NULL,
  601. };
  602.  
  603. STATIC gx_device_procs amiga_ilbm_procs =
  604. {
  605.     amiga_open_ilbm,
  606.     NULL,
  607.     NULL,
  608.     amiga_output_page_ilbm,
  609.     amiga_close_ilbm,
  610.     amiga_map_rgb_color,
  611.     amiga_map_color_rgb,
  612.     amiga_fill_rectangle_raw,
  613.     NULL,
  614.     amiga_copy_mono_raw,
  615.     amiga_copy_color_raw,
  616.     amiga_draw_line_raw,
  617.     NULL,
  618.     NULL,
  619.     NULL,
  620.     NULL,
  621.     NULL,
  622.     NULL,
  623.     NULL,
  624.     NULL,
  625.     NULL,
  626.     NULL,
  627. };
  628.  
  629.     /* Default device: opens a window on the Workbench screen and renders into it */
  630.  
  631. gx_device_amiga gs_amiga_device =
  632. {
  633.     std_device_std_body(gx_device_amiga,&amiga_default_procs,"amiga",(DEFAULT_WIDTH*72.27),(DEFAULT_HEIGHT*72.27),72.27,72.27),
  634.     { 0 },                /* std_procs */
  635.  
  636.     NULL,                /* screen */
  637.     NULL,                /* window */
  638.  
  639.     0,                /* super_width */
  640.     0,                /* super_height */
  641.     NULL,                /* super_bitmap */
  642.     NULL,                /* gadget */
  643.     NULL,                /* image */
  644.  
  645.     NULL,                /* dispatcher */
  646.     NULL,                /* main */
  647.  
  648.     NULL,                /* rport */
  649.  
  650.     NULL,                /* printer */
  651.     NULL,                /* port */
  652.     NULL,                /* colormap */
  653.     NULL,                /* bitmap */
  654.     NULL,                /* bitplane */
  655.  
  656.     1,                /* last_pen */
  657.  
  658.     DEFAULT_WIDTH,            /* page width */
  659.     DEFAULT_HEIGHT,            /* page height */
  660.     DEFAULT_FILENAME,        /* output file */
  661.     1,                /* page counter */
  662.  
  663.     0,                /* cube_size */
  664.     NULL,                /* temp_rport */
  665.     NULL,                /* temp_array */
  666.     NULL                /* pens */
  667. };
  668.  
  669.     /* Low resolution device: opens a lores custom screen and renders into it */
  670.  
  671. gx_device_amiga gs_amiga_low_device =
  672. {
  673.     std_device_std_body(gx_device_amiga,&amiga_low_procs,"amiga_low",(DEFAULT_WIDTH*72.27),(DEFAULT_HEIGHT*72.27),72.27,72.27),
  674.     { 0 },                /* std_procs */
  675.  
  676.     NULL,                /* screen */
  677.     NULL,                /* window */
  678.  
  679.     0,                /* super_width */
  680.     0,                /* super_height */
  681.     NULL,                /* super_bitmap */
  682.     NULL,                /* gadget */
  683.     NULL,                /* image */
  684.  
  685.     NULL,                /* dispatcher */
  686.     NULL,                /* main */
  687.  
  688.     NULL,                /* rport */
  689.  
  690.     NULL,                /* printer */
  691.     NULL,                /* port */
  692.     NULL,                /* colormap */
  693.     NULL,                /* bitmap */
  694.     NULL,                /* bitplane */
  695.  
  696.     1,                /* last_pen */
  697.  
  698.     DEFAULT_WIDTH,            /* page width */
  699.     DEFAULT_HEIGHT,            /* page height */
  700.     DEFAULT_FILENAME,        /* output file */
  701.     1,                /* page counter */
  702.  
  703.     0,                /* cube_size */
  704.     NULL,                /* temp_rport */
  705.     NULL,                /* temp_array */
  706.     NULL                /* pens */
  707. };
  708.  
  709.     /* High resolution device: opens a highres-interlaced custom screen */
  710.  
  711. gx_device_amiga gs_amiga_high_device =
  712. {
  713.     std_device_std_body(gx_device_amiga,&amiga_high_procs,"amiga_high",(DEFAULT_WIDTH*72.27),(DEFAULT_HEIGHT*72.27),72.27,72.27),
  714.     { 0 },                /* std_procs */
  715.  
  716.     NULL,                /* screen */
  717.     NULL,                /* window */
  718.  
  719.     0,                /* super_width */
  720.     0,                /* super_height */
  721.     NULL,                /* super_bitmap */
  722.     NULL,                /* gadget */
  723.     NULL,                /* image */
  724.  
  725.     NULL,                /* dispatcher */
  726.     NULL,                /* main */
  727.  
  728.     NULL,                /* rport */
  729.  
  730.     NULL,                /* printer */
  731.     NULL,                /* port */
  732.     NULL,                /* colormap */
  733.     NULL,                /* bitmap */
  734.     NULL,                /* bitplane */
  735.  
  736.     1,                /* last_pen */
  737.  
  738.     DEFAULT_WIDTH,            /* page width */
  739.     DEFAULT_HEIGHT,            /* page height */
  740.     DEFAULT_FILENAME,        /* output file */
  741.     1,                /* page counter */
  742.  
  743.     0,                /* cube_size */
  744.     NULL,                /* temp_rport */
  745.     NULL,                /* temp_array */
  746.     NULL                /* pens */
  747. };
  748.  
  749.     /* Super high resolution device: opens a super-highres-interlaced custom screen */
  750.  
  751. gx_device_amiga gs_amiga_super_device =
  752. {
  753.     std_device_std_body(gx_device_amiga,&amiga_super_procs,"amiga_super",(DEFAULT_WIDTH*72.27),(DEFAULT_HEIGHT*72.27),72.27,72.27),
  754.     { 0 },                /* std_procs */
  755.  
  756.     NULL,                /* screen */
  757.     NULL,                /* window */
  758.  
  759.     0,                /* super_width */
  760.     0,                /* super_height */
  761.     NULL,                /* super_bitmap */
  762.     NULL,                /* gadget */
  763.     NULL,                /* image */
  764.  
  765.     NULL,                /* dispatcher */
  766.     NULL,                /* main */
  767.  
  768.     NULL,                /* rport */
  769.  
  770.     NULL,                /* printer */
  771.     NULL,                /* port */
  772.     NULL,                /* colormap */
  773.     NULL,                /* bitmap */
  774.     NULL,                /* bitplane */
  775.  
  776.     1,                /* last_pen */
  777.  
  778.     DEFAULT_WIDTH,            /* page width */
  779.     DEFAULT_HEIGHT,            /* page height */
  780.     DEFAULT_FILENAME,        /* output file */
  781.     1,                /* page counter */
  782.  
  783.     0,                /* cube_size */
  784.     NULL,                /* temp_rport */
  785.     NULL,                /* temp_array */
  786.     NULL                /* pens */
  787. };
  788.  
  789.     /* A2024 device: opens an A2024 custom screen */
  790.  
  791. gx_device_amiga gs_amiga_a2024_device =
  792. {
  793.     std_device_std_body(gx_device_amiga,&amiga_a2024_procs,"amiga_2024",(DEFAULT_WIDTH*72.27),(DEFAULT_HEIGHT*72.27),72.27,72.27),
  794.     { 0 },                /* std_procs */
  795.  
  796.     NULL,                /* screen */
  797.     NULL,                /* window */
  798.  
  799.     0,                /* super_width */
  800.     0,                /* super_height */
  801.     NULL,                /* super_bitmap */
  802.     NULL,                /* gadget */
  803.     NULL,                /* image */
  804.  
  805.     NULL,                /* dispatcher */
  806.     NULL,                /* main */
  807.  
  808.     NULL,                /* rport */
  809.  
  810.     NULL,                /* printer */
  811.     NULL,                /* port */
  812.     NULL,                /* colormap */
  813.     NULL,                /* bitmap */
  814.     NULL,                /* bitplane */
  815.  
  816.     1,                /* last_pen */
  817.  
  818.     DEFAULT_WIDTH,            /* page width */
  819.     DEFAULT_HEIGHT,            /* page height */
  820.     DEFAULT_FILENAME,        /* output file */
  821.     1,                /* page counter */
  822.  
  823.     0,                /* cube_size */
  824.     NULL,                /* temp_rport */
  825.     NULL,                /* temp_array */
  826.     NULL                /* pens */
  827. };
  828.  
  829.     /* Picasso II device: opens a Picasso II custom screen */
  830.  
  831. gx_device_amiga gs_amiga_picassoii_device =
  832. {
  833.     std_device_std_body(gx_device_amiga,&amiga_picassoii_procs,"amiga_picassoii",(DEFAULT_WIDTH*72.27),(DEFAULT_HEIGHT*72.27),72.27,72.27),
  834.     { 0 },                /* std_procs */
  835.  
  836.     NULL,                /* screen */
  837.     NULL,                /* window */
  838.  
  839.     0,                /* super_width */
  840.     0,                /* super_height */
  841.     NULL,                /* super_bitmap */
  842.     NULL,                /* gadget */
  843.     NULL,                /* image */
  844.  
  845.     NULL,                /* dispatcher */
  846.     NULL,                /* main */
  847.  
  848.     NULL,                /* rport */
  849.  
  850.     NULL,                /* printer */
  851.     NULL,                /* port */
  852.     NULL,                /* colormap */
  853.     NULL,                /* bitmap */
  854.     NULL,                /* bitplane */
  855.  
  856.     1,                /* last_pen */
  857.  
  858.     DEFAULT_WIDTH,            /* page width */
  859.     DEFAULT_HEIGHT,            /* page height */
  860.     DEFAULT_FILENAME,        /* output file */
  861.     1,                /* page counter */
  862.  
  863.     0,                /* cube_size */
  864.     NULL,                /* temp_rport */
  865.     NULL,                /* temp_array */
  866.     NULL                /* pens */
  867. };
  868.  
  869.     /* Custom device: opens a custom screen, will ask for screen mode or check env variable. */
  870.  
  871. gx_device_amiga gs_amiga_custom_device =
  872. {
  873.     std_device_std_body(gx_device_amiga,&amiga_custom_procs,"amiga_custom",(DEFAULT_WIDTH*72.27),(DEFAULT_HEIGHT*72.27),72.27,72.27),
  874.     { 0 },                /* std_procs */
  875.  
  876.     NULL,                /* screen */
  877.     NULL,                /* window */
  878.  
  879.     0,                /* super_width */
  880.     0,                /* super_height */
  881.     NULL,                /* super_bitmap */
  882.     NULL,                /* gadget */
  883.     NULL,                /* image */
  884.  
  885.     NULL,                /* dispatcher */
  886.     NULL,                /* main */
  887.  
  888.     NULL,                /* rport */
  889.  
  890.     NULL,                /* printer */
  891.     NULL,                /* port */
  892.     NULL,                /* colormap */
  893.     NULL,                /* bitmap */
  894.     NULL,                /* bitplane */
  895.  
  896.     1,                /* last_pen */
  897.  
  898.     DEFAULT_WIDTH,            /* page width */
  899.     DEFAULT_HEIGHT,            /* page height */
  900.     DEFAULT_FILENAME,        /* output file */
  901.     1,                /* page counter */
  902.  
  903.     0,                /* cube_size */
  904.     NULL,                /* temp_rport */
  905.     NULL,                /* temp_array */
  906.     NULL                /* pens */
  907. };
  908.  
  909.     /* Printer device: renders the imagery and sends it to the printer */
  910.  
  911. gx_device_amiga gs_amiga_printer_device =
  912. {
  913.     std_device_std_body(gx_device_amiga,&amiga_printer_procs,"amiga_printer",(DEFAULT_WIDTH*72.27),(DEFAULT_HEIGHT*72.27),72.27,72.27),
  914.     { 0 },                /* std_procs */
  915.  
  916.     NULL,                /* screen */
  917.     NULL,                /* window */
  918.  
  919.     0,                /* super_width */
  920.     0,                /* super_height */
  921.     NULL,                /* super_bitmap */
  922.     NULL,                /* gadget */
  923.     NULL,                /* image */
  924.  
  925.     NULL,                /* dispatcher */
  926.     NULL,                /* main */
  927.  
  928.     NULL,                /* rport */
  929.  
  930.     NULL,                /* printer */
  931.     NULL,                /* port */
  932.     NULL,                /* colormap */
  933.     NULL,                /* bitmap */
  934.     NULL,                /* bitplane */
  935.  
  936.     1,                /* last_pen */
  937.  
  938.     DEFAULT_WIDTH,            /* page width */
  939.     DEFAULT_HEIGHT,            /* page height */
  940.     DEFAULT_FILENAME,        /* output file */
  941.     1,                /* page counter */
  942.  
  943.     0,                /* cube_size */
  944.     NULL,                /* temp_rport */
  945.     NULL,                /* temp_array */
  946.     NULL                /* pens */
  947. };
  948.  
  949.     /* ILBM device: renders the imagery and saves it to an IFF-ILBM file. */
  950.  
  951. gx_device_amiga gs_amiga_ilbm_device =
  952. {
  953.     std_device_std_body(gx_device_amiga,&amiga_ilbm_procs,"amiga_ilbm",(DEFAULT_WIDTH*72.27),(DEFAULT_HEIGHT*72.27),72.27,72.27),
  954.     { 0 },                /* std_procs */
  955.  
  956.     NULL,                /* screen */
  957.     NULL,                /* window */
  958.  
  959.     0,                /* super_width */
  960.     0,                /* super_height */
  961.     NULL,                /* super_bitmap */
  962.     NULL,                /* gadget */
  963.     NULL,                /* image */
  964.  
  965.     NULL,                /* dispatcher */
  966.     NULL,                /* main */
  967.  
  968.     NULL,                /* rport */
  969.  
  970.     NULL,                /* printer */
  971.     NULL,                /* port */
  972.     NULL,                /* colormap */
  973.     NULL,                /* bitmap */
  974.     NULL,                /* bitplane */
  975.  
  976.     1,                /* last_pen */
  977.  
  978.     DEFAULT_WIDTH,            /* page width */
  979.     DEFAULT_HEIGHT,            /* page height */
  980.     DEFAULT_FILENAME,        /* output file */
  981.     1,                /* page counter */
  982.  
  983.     0,                /* cube_size */
  984.     NULL,                /* temp_rport */
  985.     NULL,                /* temp_array */
  986.     NULL                /* pens */
  987. };
  988.  
  989.     /* Dark (black) and light (white) rendering colours; the default device
  990.      * determines the actual colours to be used by looking into the screen
  991.      * colour lookup table, the other device drivers leave these values
  992.      * untouched.
  993.      */
  994.  
  995. STATIC UBYTE    DarkPen        = 0,
  996.         LightPen    = 1;
  997.  
  998.     /* Cheap, but effective ;-) */
  999.  
  1000. #define xdev ((gx_device_amiga *)dev)
  1001.  
  1002.     /* set_mono_device(gx_device_amiga *dev,int cube_size,LONG *pens):
  1003.      *
  1004.      *    Reconfigure a device for monochrome output.
  1005.      */
  1006.  
  1007. VOID
  1008. set_mono_device(gx_device_amiga *dev)
  1009. {
  1010.     xdev -> color_info . depth        = 1;
  1011.     xdev -> color_info . num_components    = 1;
  1012.     xdev -> color_info . max_gray        = 1;
  1013.     xdev -> color_info . max_color        = 0;
  1014.     xdev -> color_info . dither_grays    = 2;
  1015.     xdev -> color_info . dither_colors    = 0;
  1016.  
  1017.     xdev -> std_procs . copy_color        = amiga_copy_color;
  1018.     xdev -> std_procs . map_rgb_color    = amiga_map_rgb_color;
  1019.     xdev -> std_procs . map_color_rgb    = amiga_map_color_rgb;
  1020.  
  1021.     xdev -> cube_size            = 0;
  1022. }
  1023.  
  1024.     /* set_colour_device(gx_device_amiga *dev,int cube_size,LONG *pens):
  1025.      *
  1026.      *    Reconfigure a device for colour output.
  1027.      */
  1028.  
  1029. VOID
  1030. set_colour_device(gx_device_amiga *dev,int cube_size,LONG *pens)
  1031. {
  1032.     xdev -> color_info . depth        = 8;
  1033.     xdev -> color_info . num_components    = 3;
  1034.     xdev -> color_info . max_gray        = cube_size - 1;
  1035.     xdev -> color_info . max_color        = cube_size - 1;
  1036.     xdev -> color_info . dither_grays    = cube_size;
  1037.     xdev -> color_info . dither_colors    = cube_size;
  1038.  
  1039.     xdev -> std_procs . copy_color        = amiga_copy_color8;
  1040.  
  1041.         /* Any colours to be remapped? */
  1042.  
  1043.     if(pens)
  1044.     {
  1045.         xdev -> std_procs . map_rgb_color    = amiga_color_map_rgb_color_pen;
  1046.         xdev -> std_procs . map_color_rgb    = amiga_color_map_color_rgb_pen;
  1047.         xdev -> pens                = pens;
  1048.     }
  1049.     else
  1050.     {
  1051.         xdev -> std_procs . map_rgb_color    = amiga_color_map_rgb_color;
  1052.         xdev -> std_procs . map_color_rgb    = amiga_color_map_color_rgb;
  1053.     }
  1054.  
  1055.         /* Remember the size of the RGB cube. */
  1056.  
  1057.     xdev -> cube_size            = cube_size;
  1058. }
  1059.  
  1060.     /* set_colour_printer_device(gx_device_amiga *dev,LONG CubeSize):
  1061.      *
  1062.      *    Configure the printer device for colour output.
  1063.      */
  1064.  
  1065. VOID
  1066. set_colour_printer_device(gx_device_amiga *dev,LONG CubeSize)
  1067. {
  1068.     xdev -> color_info . depth        = 16;
  1069.     xdev -> color_info . num_components    = 3;
  1070.     xdev -> color_info . max_gray        = CubeSize - 1;
  1071.     xdev -> color_info . max_color        = CubeSize - 1;
  1072.     xdev -> color_info . dither_grays    = CubeSize;
  1073.     xdev -> color_info . dither_colors    = CubeSize;
  1074.  
  1075.     xdev -> std_procs . fill_rectangle    = amiga_fill_rectangle_raw_color;
  1076.     xdev -> std_procs . copy_mono        = amiga_copy_mono_raw_color;
  1077.     xdev -> std_procs . copy_color        = amiga_copy_color_raw_color16;
  1078.     xdev -> std_procs . draw_line        = amiga_draw_line_raw_color;
  1079.     xdev -> std_procs . map_rgb_color    = amiga_color_map_rgb_color;
  1080.     xdev -> std_procs . map_color_rgb    = amiga_color_map_color_rgb;
  1081.     xdev -> cube_size            = CubeSize;
  1082. }
  1083.  
  1084.     /* DeleteBitMap(struct BitMap *BitMap,BOOL Private):
  1085.      *
  1086.      *    Free memory associated with a custom rendering bitmap.
  1087.      */
  1088.  
  1089. VOID
  1090. DeleteBitMap(struct BitMap *BitMap,BOOL Private)
  1091. {
  1092.     if(GfxBase -> LibNode . lib_Version >= 39 && !Private)
  1093.         FreeBitMap(BitMap);
  1094.     else
  1095.     {
  1096.         LONG i;
  1097.  
  1098.         for(i = 0 ; i < BitMap -> Depth ; i++)
  1099.         {
  1100.             if(BitMap -> Planes[i])
  1101.                 FreeVec(BitMap -> Planes[i]);
  1102.         }
  1103.  
  1104.         FreeVec(BitMap);
  1105.     }
  1106. }
  1107.  
  1108.     /* CreateBitMap(LONG Width,LONG Height,LONG Depth,ULONG Flags,struct BitMap *Friend,BOOL Private):
  1109.      *
  1110.      *    Create a custom rendering bitmap.
  1111.      */
  1112.  
  1113. struct BitMap *
  1114. CreateBitMap(LONG Width,LONG Height,LONG Depth,ULONG Flags,struct BitMap *Friend,BOOL Private)
  1115. {
  1116.     if(GfxBase -> LibNode . lib_Version >= 39 && !Private)
  1117.         return(AllocBitMap(Width,Height,Depth,Flags,Friend));
  1118.     else
  1119.     {
  1120.         struct BitMap    *BitMap;
  1121.         LONG         Plus;
  1122.         ULONG         MemType;
  1123.  
  1124.             /* Bitmap structure needs to be padded if more
  1125.              * than the standard eight bitplanes are to be
  1126.              * allocated.
  1127.              */
  1128.  
  1129.         if(Depth > 8)
  1130.             Plus = (Depth - 8) * sizeof(PLANEPTR);
  1131.         else
  1132.             Plus = 0;
  1133.  
  1134.         if(Private)
  1135.             MemType = MEMF_ANY;
  1136.         else
  1137.             MemType = MEMF_CHIP;
  1138.  
  1139.         if((BitMap = (struct BitMap *)AllocVec(sizeof(struct BitMap) + Plus,MEMF_ANY | MEMF_CLEAR)) != NULL)
  1140.         {
  1141.             LONG i,PageSize;
  1142.  
  1143.             InitBitMap(BitMap,Depth,Width,Height);
  1144.  
  1145.             PageSize = BitMap -> BytesPerRow * BitMap -> Rows;
  1146.  
  1147.             for(i = 0 ; i < BitMap -> Depth ; i++)
  1148.             {
  1149.                 if(!(BitMap -> Planes[i] = (PLANEPTR)AllocVec(PageSize,MemType)))
  1150.                 {
  1151.                     LONG j;
  1152.  
  1153.                     for(j = 0 ; j < i ; j++)
  1154.                         FreeVec(BitMap -> Planes[j]);
  1155.  
  1156.                     FreeVec(BitMap);
  1157.  
  1158.                     return(NULL);
  1159.                 }
  1160.             }
  1161.  
  1162.             return(BitMap);
  1163.         }
  1164.  
  1165.         return(NULL);
  1166.     }
  1167. }
  1168.  
  1169.     /* DeleteTempRPort(struct RastPort *Temp):
  1170.      *
  1171.      *    Free memory associated with a temporary raster port.
  1172.      */
  1173.  
  1174. VOID
  1175. DeleteTempRPort(struct RastPort *Temp)
  1176. {
  1177.     DeleteBitMap(Temp -> BitMap,FALSE);
  1178.  
  1179.     FreeVec(Temp);
  1180. }
  1181.  
  1182.     /* CreateTempRPort(struct RastPort *Source):
  1183.      *
  1184.      *    Allocate memory for temporary raster port (one line high).
  1185.      */
  1186.  
  1187. struct RastPort *
  1188. CreateTempRPort(struct RastPort *Source)
  1189. {
  1190.     struct RastPort *Temp;
  1191.  
  1192.     if((Temp = (struct RastPort *)AllocVec(sizeof(struct RastPort),MEMF_ANY)) != NULL)
  1193.     {
  1194.         LONG Width,Depth;
  1195.  
  1196.         CopyMem(Source,Temp,sizeof(struct RastPort));
  1197.  
  1198.         Temp -> Layer = NULL;
  1199.  
  1200.         if(GfxBase -> LibNode . lib_Version >= 39)
  1201.         {
  1202.             Width    = GetBitMapAttr(Source -> BitMap,BMA_WIDTH);
  1203.             Depth    = GetBitMapAttr(Source -> BitMap,BMA_DEPTH);
  1204.         }
  1205.         else
  1206.         {
  1207.             Width    = Source -> BitMap -> BytesPerRow * 8;
  1208.             Depth    = Source -> BitMap -> Depth;
  1209.         }
  1210.  
  1211.         if((Temp -> BitMap = CreateBitMap((Width + 15) & ~15,1,Depth,NULL,Source -> BitMap,FALSE)) != NULL)
  1212.             return(Temp);
  1213.         else
  1214.             FreeVec(Temp);
  1215.     }
  1216.  
  1217.     return(NULL);
  1218. }
  1219.  
  1220.     /* Euclid(LONG a,LONG b):
  1221.      *
  1222.      *    Compute the greatest common divisor of two integers.
  1223.      */
  1224.  
  1225. LONG
  1226. Euclid(LONG a,LONG b)
  1227. {
  1228.     do
  1229.     {
  1230.         if(a < b)
  1231.         {
  1232.             LONG t;
  1233.  
  1234.             t = a;
  1235.             a = b;
  1236.             b = t;
  1237.         }
  1238.  
  1239.         a = a % b;
  1240.     }
  1241.     while(a);
  1242.  
  1243.     return(b);
  1244. }
  1245.  
  1246.     /* PutDump(register BYTE *Destination,register LONG Count):
  1247.      *
  1248.      *    Store a byte dump.
  1249.      */
  1250.  
  1251. BYTE *
  1252. PutDump(register BYTE *Destination,register LONG Count)
  1253. {
  1254.     register BYTE *Source = Buffer;
  1255.  
  1256.     *Destination++     = Count - 1;
  1257.      PackedBytes    += Count + 1;
  1258.  
  1259.     while(Count--)
  1260.         *Destination++ = *Source++;
  1261.  
  1262.     return(Destination);
  1263. }
  1264.  
  1265.     /* PutRun(register BYTE *Destination,LONG Count,WORD Char):
  1266.      *
  1267.      *    Store a byte run.
  1268.      */
  1269.  
  1270. BYTE *
  1271. PutRun(register BYTE *Destination,LONG Count,WORD Char)
  1272. {
  1273.     *Destination++     = -(Count - 1);
  1274.     *Destination++     = Char;
  1275.      PackedBytes    += 2;
  1276.  
  1277.     return(Destination);
  1278. }
  1279.  
  1280.     /* PackRow(PLANEPTR *SourcePtr,register BYTE *Destination,LONG RowSize):
  1281.      *
  1282.      *    Pack a raster line using the CmpByteRun1 algorithm.
  1283.      */
  1284.  
  1285. LONG
  1286. PackRow(PLANEPTR *SourcePtr,register BYTE *Destination,LONG RowSize)
  1287. {
  1288.     register BYTE *Source = *SourcePtr;
  1289.  
  1290.     WORD    Buffered    = 1,
  1291.         RunStart    = 0;
  1292.     BYTE    Mode        = DUMP,
  1293.         LastChar,
  1294.         Char;
  1295.  
  1296.     PackedBytes = 0;
  1297.  
  1298.     Buffer[0] = LastChar = Char = *Source++;
  1299.  
  1300.     RowSize--;
  1301.  
  1302.     while(RowSize--)
  1303.     {
  1304.         Buffer[Buffered++] = Char = *Source++;
  1305.  
  1306.         if(Mode)
  1307.         {
  1308.             if((Char != LastChar) || (Buffered - RunStart > MAXRUN))
  1309.             {
  1310.                 Destination    = PutRun(Destination,Buffered - 1 - RunStart,LastChar);
  1311.                 Buffer[0]    = Char;
  1312.                 Buffered    = 1;
  1313.                 RunStart    = 0;
  1314.                 Mode        = DUMP;
  1315.             }
  1316.         }
  1317.         else
  1318.         {
  1319.             if(Buffered > MAXDAT)
  1320.             {
  1321.                 Destination    = PutDump(Destination,Buffered - 1);
  1322.                 Buffer[0]    = Char;
  1323.                 Buffered    = 1;
  1324.                 RunStart    = 0;
  1325.             }
  1326.             else
  1327.             {
  1328.                 if(Char == LastChar)
  1329.                 {
  1330.                     if(Buffered - RunStart >= MINRUN)
  1331.                     {
  1332.                         if(RunStart)
  1333.                             Destination = PutDump(Destination,RunStart);
  1334.  
  1335.                         Mode = RUN;
  1336.                     }
  1337.                     else
  1338.                     {
  1339.                         if(!RunStart)
  1340.                             Mode = RUN;
  1341.                     }
  1342.                 }
  1343.                 else
  1344.                     RunStart = Buffered - 1;
  1345.             }
  1346.         }
  1347.  
  1348.         LastChar = Char;
  1349.     }
  1350.  
  1351.     if(Mode)
  1352.         PutRun(Destination,Buffered - RunStart,LastChar);
  1353.     else
  1354.         PutDump(Destination,Buffered);
  1355.  
  1356.     *SourcePtr = Source;
  1357.  
  1358.     return(PackedBytes);
  1359. }
  1360.  
  1361.     /* PutBODY(struct IFFHandle *Handle,struct BitMap *BitMap):
  1362.      *
  1363.      *    Store a bitmap in a BODY chunk.
  1364.      */
  1365.  
  1366. BOOL
  1367. PutBODY(struct IFFHandle *Handle,struct BitMap *BitMap)
  1368. {
  1369.     PLANEPTR    *Planes;
  1370.     BYTE        *PackBuffer;
  1371.     BOOL         Success = FALSE;
  1372.     LONG         PackedBytes,
  1373.              i,j;
  1374.  
  1375.         /* Allocate the bitplane information. */
  1376.  
  1377.     if((Planes = (PLANEPTR *)AllocVec(BitMap -> Depth * sizeof(PLANEPTR *),MEMF_ANY | MEMF_CLEAR)) != NULL)
  1378.     {
  1379.             /* Allocate the compression buffer. */
  1380.  
  1381.         if((PackBuffer = (BYTE *)AllocVec(BitMap -> BytesPerRow * 2,MEMF_ANY)) != NULL)
  1382.         {
  1383.                 /* Copy the planes over. */
  1384.  
  1385.             for(i = 0 ; i < BitMap -> Depth ; i++)
  1386.                 Planes[i] = BitMap -> Planes[i];
  1387.  
  1388.             if(!PushChunk(Handle,0,ID_BODY,IFFSIZE_UNKNOWN))
  1389.             {
  1390.                 Success = TRUE;
  1391.  
  1392.                     /* Run down the rows. */
  1393.  
  1394.                 for(i = 0 ; Success && i < BitMap -> Rows ; i++)
  1395.                 {
  1396.                     for(j = 0 ; Success && j < BitMap -> Depth ; j++)
  1397.                     {
  1398.                             /* Pack the data. */
  1399.  
  1400.                         PackedBytes = PackRow(&Planes[j],PackBuffer,BitMap -> BytesPerRow);
  1401.  
  1402.                             /* Write it to disk. */
  1403.  
  1404.                         if(WriteChunkRecords(Handle,PackBuffer,PackedBytes,1) != 1)
  1405.                             Success = FALSE;
  1406.                     }
  1407.                 }
  1408.  
  1409.                 if(PopChunk(Handle))
  1410.                     Success = FALSE;
  1411.             }
  1412.  
  1413.             FreeVec(PackBuffer);
  1414.         }
  1415.  
  1416.         FreeVec(Planes);
  1417.     }
  1418.  
  1419.     return(Success);
  1420. }
  1421.  
  1422.     /* PutANNO(struct IFFHandle *Handle):
  1423.      *
  1424.      *    Store annotation chunk.
  1425.      */
  1426.  
  1427. BOOL
  1428. PutANNO(struct IFFHandle *Handle)
  1429. {
  1430.     STATIC STRPTR Note = "Rendered by GNU Ghostscript 2.6.1.4";
  1431.  
  1432.     if(!PushChunk(Handle,0,ID_ANNO,strlen(Note)))
  1433.     {
  1434.         if(WriteChunkRecords(Handle,Note,strlen(Note),1) == 1)
  1435.         {
  1436.             if(!PopChunk(Handle))
  1437.                 return(TRUE);
  1438.         }
  1439.     }
  1440.  
  1441.     return(FALSE);
  1442. }
  1443.  
  1444.     /* PutCAMG(struct IFFHandle *Handle):
  1445.      *
  1446.      *    Store display mode chunk.
  1447.      */
  1448.  
  1449. BOOL
  1450. PutCAMG(struct IFFHandle *Handle)
  1451. {
  1452.     ULONG ViewModes = HIRESLACE_KEY;
  1453.  
  1454.     if(!PushChunk(Handle,0,ID_CAMG,sizeof(ULONG)))
  1455.     {
  1456.         if(WriteChunkRecords(Handle,&ViewModes,sizeof(ULONG),1) == 1)
  1457.         {
  1458.             if(!PopChunk(Handle))
  1459.                 return(TRUE);
  1460.         }
  1461.     }
  1462.  
  1463.     return(FALSE);
  1464. }
  1465.  
  1466.     /* PutCMAP(struct IFFHandle *Handle):
  1467.      *
  1468.      *    Store colour map chunk.
  1469.      */
  1470.  
  1471. BOOL
  1472. PutCMAP(struct IFFHandle *Handle)
  1473. {
  1474.     STATIC UBYTE Colours[2][3] =
  1475.     {
  1476.         0x00,0x00,0x00,
  1477.         0xFF,0xFF,0xFF
  1478.     };
  1479.  
  1480.     if(!PushChunk(Handle,0,ID_CMAP,sizeof(Colours)))
  1481.     {
  1482.         if(WriteChunkRecords(Handle,Colours,2,3) == 3)
  1483.         {
  1484.             if(!PopChunk(Handle))
  1485.                 return(TRUE);
  1486.         }
  1487.     }
  1488.  
  1489.     return(FALSE);
  1490. }
  1491.  
  1492.     /* PutDPI(struct IFFHandle *Handle,UWORD X_DPI,UWORD Y_DPI):
  1493.      *
  1494.      *    Store DPI chunk.
  1495.      */
  1496.  
  1497. BOOL
  1498. PutDPI(struct IFFHandle *Handle,UWORD X_DPI,UWORD Y_DPI)
  1499. {
  1500.     DPIHeader Header;
  1501.  
  1502.     Header . dpi_x = X_DPI;
  1503.     Header . dpi_y = Y_DPI;
  1504.  
  1505.     if(!PushChunk(Handle,0,ID_DPI,sizeof(Header)))
  1506.     {
  1507.         if(WriteChunkRecords(Handle,&Header,sizeof(Header),1) == 1)
  1508.         {
  1509.             if(!PopChunk(Handle))
  1510.                 return(TRUE);
  1511.         }
  1512.     }
  1513.  
  1514.     return(FALSE);
  1515. }
  1516.  
  1517.     /* PutBMHD(struct IFFHandle *Handle,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI):
  1518.      *
  1519.      *    Store BMHD chunk.
  1520.      */
  1521.  
  1522. BOOL
  1523. PutBMHD(struct IFFHandle *Handle,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI)
  1524. {
  1525.         /* Valid parameters? */
  1526.  
  1527.     if(X_DPI > 0 && Y_DPI > 0 && Width > 0 && Height > 0)
  1528.     {
  1529.         BitMapHeader    Header;
  1530.         UWORD        gcd;
  1531.  
  1532.             /* So we can store neat & small
  1533.              * aspect ration values.
  1534.              */
  1535.  
  1536.         gcd = Euclid(X_DPI,Y_DPI);
  1537.  
  1538.         Header . w            = Width;
  1539.         Header . h            = Height;
  1540.         Header . pageWidth        = Width;
  1541.         Header . pageHeight        = Height;
  1542.         Header . x            = 0;
  1543.         Header . y            = 0;
  1544.         Header . nPlanes        = 1;
  1545.         Header . masking        = 0;
  1546.         Header . compression        = 1;
  1547.         Header . pad1            = 0;
  1548.         Header . transparentColor    = 0;
  1549.         Header . xAspect        = X_DPI / gcd;
  1550.         Header . yAspect        = Y_DPI / gcd;
  1551.  
  1552.         if(!PushChunk(Handle,0,ID_BMHD,sizeof(Header)))
  1553.         {
  1554.             if(WriteChunkRecords(Handle,&Header,sizeof(Header),1) == 1)
  1555.             {
  1556.                 if(!PopChunk(Handle))
  1557.                     return(TRUE);
  1558.             }
  1559.         }
  1560.     }
  1561.  
  1562.     return(FALSE);
  1563. }
  1564.  
  1565.     /* SaveBitMap(STRPTR Name,struct BitMap *BitMap,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI):
  1566.      *
  1567.      *    Store a bitmap in an IFF-ILBM file.
  1568.      */
  1569.  
  1570. BOOL
  1571. SaveBitMap(STRPTR Name,struct BitMap *BitMap,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI)
  1572. {
  1573.     struct IFFHandle    *Handle;
  1574.     BOOL             Success = FALSE;
  1575.  
  1576.     if((Handle = AllocIFF()) != NULL)
  1577.     {
  1578.         if((Handle -> iff_Stream = Open(Name,MODE_NEWFILE)) != NULL)
  1579.         {
  1580.             InitIFFasDOS(Handle);
  1581.  
  1582.             if(!OpenIFF(Handle,IFFF_WRITE))
  1583.             {
  1584.                 if(!PushChunk(Handle,ID_ILBM,ID_FORM,IFFSIZE_UNKNOWN))
  1585.                 {
  1586.                     if(PutBMHD(Handle,Width,Height,X_DPI,Y_DPI))
  1587.                     {
  1588.                         if(PutANNO(Handle))
  1589.                         {
  1590.                             if(PutCMAP(Handle))
  1591.                             {
  1592.                                 if(PutCAMG(Handle))
  1593.                                 {
  1594.                                     if(PutDPI(Handle,X_DPI,Y_DPI))
  1595.                                     {
  1596.                                         if(PutBODY(Handle,BitMap))
  1597.                                             Success = TRUE;
  1598.                                     }
  1599.                                 }
  1600.                             }
  1601.                         }
  1602.                     }
  1603.  
  1604.                     if(PopChunk(Handle))
  1605.                         Success = FALSE;
  1606.                 }
  1607.  
  1608.                 CloseIFF(Handle);
  1609.             }
  1610.  
  1611.             Close(Handle -> iff_Stream);
  1612.  
  1613.             if(!Success)
  1614.                 DeleteFile(Name);
  1615.         }
  1616.  
  1617.         FreeIFF(Handle);
  1618.     }
  1619.  
  1620.     return(Success);
  1621. }
  1622.  
  1623.     /* GetInches(STRPTR Buffer):
  1624.      *
  1625.      *    Turn a parameter string into a number representing
  1626.      *    a certain number of inches.
  1627.      */
  1628.  
  1629. double
  1630. GetInches(STRPTR Buffer)
  1631. {
  1632.     STATIC struct { STRPTR Unit; float Factor; } Units[7] =
  1633.     {
  1634.         "pt",    1.0,            /* Point */
  1635.         "pc",    12.0,            /* Pica */
  1636.         "in",    72.72,            /* Inch */
  1637.         "cm",    72.72 / 2.54,        /* Centimeter */
  1638.         "mm",    727.2 / 2.54,        /* Millimeter */
  1639.         "dd",    1157.0 / 1238.0,    /* Didot point */
  1640.         "cc",    1157.0 / 103.0        /* Cicero */
  1641.     };
  1642.  
  1643.     UBYTE    Temp[40];
  1644.     float    Value;
  1645.     LONG    i;
  1646.  
  1647.     i = 0;
  1648.  
  1649.         /* Strip the numeric part. */
  1650.  
  1651.     while((Buffer[i] >= '0' && Buffer[i] <= '9') || Buffer[i] == '.' || Buffer[i] == '+' || Buffer[i] == '-' || Buffer[i] == 'e')
  1652.     {
  1653.         Temp[i] = Buffer[i];
  1654.  
  1655.         i++;
  1656.     }
  1657.  
  1658.         /* Provide null-termination. */
  1659.  
  1660.     Temp[i] = 0;
  1661.  
  1662.         /* atof() appears to be broken in ixemul.library 39.45. */
  1663.  
  1664.     sscanf(Temp,"%f",&Value);
  1665.  
  1666.     Buffer += i;
  1667.  
  1668.         /* Which measuring unit? */
  1669.  
  1670.     for(i = 0 ; i < 7 ; i++)
  1671.     {
  1672.             /* Return the result in inches. */
  1673.  
  1674.         if(!Stricmp(Buffer,Units[i] . Unit))
  1675.             return(Value * Units[i] . Factor / 72.27);
  1676.     }
  1677.  
  1678.         /* Return the result in inches. */
  1679.  
  1680.     return(Value / 72.27);
  1681. }
  1682.  
  1683.     /* DispatchTask():
  1684.      *
  1685.      *    Asynchronous window message dispatcher.
  1686.      */
  1687.  
  1688. VOID
  1689. DispatchTask()
  1690. {
  1691.     struct Task    *me;
  1692.     gx_device    *dev;
  1693.  
  1694.         /* Set up global data area base register. */
  1695. #ifdef IXEMUL
  1696.     ix_geta4();
  1697. #endif
  1698.         /* Who am I? */
  1699.  
  1700.     me = FindTask(NULL);
  1701.  
  1702.         /* Wait for wakeup call. */
  1703.  
  1704.     Wait(SIG_WAKEUP);
  1705.  
  1706.         /* Obtain device pointer. */
  1707.  
  1708.     dev = me -> tc_UserData;
  1709.  
  1710.         /* Enable user input. */
  1711.  
  1712.     if(ModifyIDCMP(xdev -> window,IDCMP_FLAGS))
  1713.     {
  1714.         ULONG    Mask = 1 << xdev -> window -> UserPort -> mp_SigBit,
  1715.             Set;
  1716.         BOOL    Done = FALSE;
  1717.  
  1718.             /* Fill in the dispatcher entry. */
  1719.  
  1720.         xdev -> dispatcher = me;
  1721.  
  1722.             /* Ring back. */
  1723.  
  1724.         Signal((struct Task *)xdev -> main,SIG_HANDSHAKE);
  1725.  
  1726.             /* Wait for input... */
  1727.  
  1728.         do
  1729.         {
  1730.             Set = Wait(Mask | SIG_KILL);
  1731.  
  1732.             if(Set & Mask)
  1733.                 DispatchSuperWindow(dev);
  1734.  
  1735.             if(Set & SIG_KILL)
  1736.                 Done = TRUE;
  1737.         }
  1738.         while(!Done);
  1739.  
  1740.             /* Disable user input. */
  1741.  
  1742.         ModifyIDCMP(xdev -> window,NULL);
  1743.     }
  1744.  
  1745.         /* Disable task switching. */
  1746.  
  1747.     Forbid();
  1748.  
  1749.         /* Clear the dispatcher entry. */
  1750.  
  1751.     xdev -> dispatcher = NULL;
  1752.  
  1753.         /* Signal the main process that we are done. */
  1754.  
  1755.     Signal((struct Task *)xdev -> main,SIG_HANDSHAKE);
  1756.  
  1757.         /* Remove ourselves. */
  1758.  
  1759.     RemTask(NULL);
  1760. }
  1761.  
  1762.     /* DeleteScrollers(gx_device *dev):
  1763.      *
  1764.      *    Delete the window border scrollers.
  1765.      */
  1766.  
  1767. VOID
  1768. DeleteScrollers(gx_device *dev)
  1769. {
  1770.     if(xdev -> gadget)
  1771.     {
  1772.         if(xdev -> gadget[HORIZONTAL_SCROLLER])
  1773.             DisposeObject(xdev -> gadget[HORIZONTAL_SCROLLER]);
  1774.  
  1775.         if(xdev -> gadget[VERTICAL_SCROLLER])
  1776.             DisposeObject(xdev -> gadget[VERTICAL_SCROLLER]);
  1777.  
  1778.         if(xdev -> gadget[UP_ARROW])
  1779.             DisposeObject(xdev -> gadget[UP_ARROW]);
  1780.  
  1781.         if(xdev -> gadget[DOWN_ARROW])
  1782.             DisposeObject(xdev -> gadget[DOWN_ARROW]);
  1783.  
  1784.         if(xdev -> gadget[LEFT_ARROW])
  1785.             DisposeObject(xdev -> gadget[LEFT_ARROW]);
  1786.  
  1787.         if(xdev -> gadget[RIGHT_ARROW])
  1788.             DisposeObject(xdev -> gadget[RIGHT_ARROW]);
  1789.  
  1790.         FreeVec(xdev -> gadget);
  1791.  
  1792.         xdev -> gadget = NULL;
  1793.     }
  1794.  
  1795.     if(xdev -> image)
  1796.     {
  1797.         if(xdev -> image[UP_IMAGE])
  1798.             DisposeObject(xdev -> image[UP_IMAGE]);
  1799.  
  1800.         if(xdev -> image[DOWN_IMAGE])
  1801.             DisposeObject(xdev -> image[DOWN_IMAGE]);
  1802.  
  1803.         if(xdev -> image[LEFT_IMAGE])
  1804.             DisposeObject(xdev -> image[LEFT_IMAGE]);
  1805.  
  1806.         if(xdev -> image[RIGHT_IMAGE])
  1807.             DisposeObject(xdev -> image[RIGHT_IMAGE]);
  1808.  
  1809.         FreeVec(xdev -> image);
  1810.  
  1811.         xdev -> image = NULL;
  1812.     }
  1813. }
  1814.  
  1815.     /* CreateScrollers(gx_device *dev,struct Screen *Screen):
  1816.      *
  1817.      *    Create the window border scroller handles.
  1818.      */
  1819.  
  1820. BOOL
  1821. CreateScrollers(gx_device *dev,struct Screen *Screen)
  1822. {
  1823.     BOOL Result = FALSE;
  1824.  
  1825.     if((xdev -> gadget = (struct Gadget **)AllocVec(sizeof(struct Gadget *) * GADGET_COUNT,MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC)) != NULL)
  1826.     {
  1827.         if((xdev -> image = (struct Image **)AllocVec(sizeof(struct Image *) * IMAGE_COUNT,MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC)) != NULL)
  1828.         {
  1829.             struct DrawInfo *DrawInfo;
  1830.  
  1831.             if((DrawInfo = GetScreenDrawInfo(Screen)) != NULL)
  1832.             {
  1833.                 ULONG     SizeWidth,
  1834.                      SizeHeight;
  1835.                 ULONG     ArrowWidth,
  1836.                      ArrowHeight;
  1837.                 UWORD     SizeType;
  1838.                 Object    *SizeImage;
  1839.  
  1840.                 if(Screen -> Flags & SCREENHIRES)
  1841.                 {
  1842.                     SizeWidth    = 18;
  1843.                     SizeHeight    = 10;
  1844.  
  1845.                     SizeType    = SYSISIZE_MEDRES;
  1846.                 }
  1847.                 else
  1848.                 {
  1849.                     SizeWidth    = 13;
  1850.                     SizeHeight    = 11;
  1851.  
  1852.                     SizeType    = SYSISIZE_LOWRES;
  1853.                 }
  1854.  
  1855.                 if((SizeImage = NewObject(NULL,SYSICLASS,
  1856.                     SYSIA_Size,    SizeType,
  1857.                     SYSIA_Which,    SIZEIMAGE,
  1858.                     SYSIA_DrawInfo,    DrawInfo,
  1859.                 TAG_DONE)) != NULL)
  1860.                 {
  1861.                     GetAttr(IA_Width,    SizeImage,&SizeWidth);
  1862.                     GetAttr(IA_Height,    SizeImage,&SizeHeight);
  1863.  
  1864.                     DisposeObject(SizeImage);
  1865.                 }
  1866.  
  1867.                 if((xdev -> image[UP_IMAGE] = (struct Image *)NewObject(NULL,"sysiclass",
  1868.                     SYSIA_Size,    SizeType,
  1869.                     SYSIA_Which,    UPIMAGE,
  1870.                     SYSIA_DrawInfo,    DrawInfo,
  1871.                 TAG_DONE)) != NULL)
  1872.                 {
  1873.                     GetAttr(IA_Height,xdev -> image[UP_IMAGE],&ArrowHeight);
  1874.  
  1875.                     if((xdev -> image[DOWN_IMAGE] = (struct Image *)NewObject(NULL,"sysiclass",
  1876.                         SYSIA_Size,    SizeType,
  1877.                         SYSIA_Which,    DOWNIMAGE,
  1878.                         SYSIA_DrawInfo,    DrawInfo,
  1879.                     TAG_DONE)) != NULL)
  1880.                     {
  1881.                         if((xdev -> image[LEFT_IMAGE] = (struct Image *)NewObject(NULL,"sysiclass",
  1882.                             SYSIA_Size,    SizeType,
  1883.                             SYSIA_Which,    LEFTIMAGE,
  1884.                             SYSIA_DrawInfo,    DrawInfo,
  1885.                         TAG_DONE)) != NULL)
  1886.                         {
  1887.                             GetAttr(IA_Width,xdev -> image[LEFT_IMAGE],&ArrowWidth);
  1888.  
  1889.                             if((xdev -> image[RIGHT_IMAGE] = (struct Image *)NewObject(NULL,"sysiclass",
  1890.                                 SYSIA_Size,    SizeType,
  1891.                                 SYSIA_Which,    RIGHTIMAGE,
  1892.                                 SYSIA_DrawInfo,    DrawInfo,
  1893.                             TAG_DONE)) != NULL)
  1894.                             {
  1895.                                 if((xdev -> gadget[VERTICAL_SCROLLER] = NewObject(NULL,"propgclass",
  1896.                                     GA_ID,        VERTICAL_SCROLLER,
  1897.  
  1898.                                     GA_Top,        Screen -> WBorTop + Screen -> Font -> ta_YSize + 2,
  1899.                                     GA_RelHeight,    -(Screen -> WBorTop + Screen -> Font -> ta_YSize + 2 + SizeHeight + 1 + 2 * ArrowHeight),
  1900.                                     GA_Width,    SizeWidth - 8,
  1901.                                     GA_RelRight,    -(SizeWidth - 5),
  1902.  
  1903.                                     GA_GZZGadget,    TRUE,
  1904.                                     GA_Immediate,    TRUE,
  1905.                                     GA_FollowMouse,    TRUE,
  1906.                                     GA_RelVerify,    TRUE,
  1907.                                     GA_RightBorder,    TRUE,
  1908.  
  1909.                                     PGA_Freedom,    FREEVERT,
  1910.                                     PGA_NewLook,    TRUE,
  1911.                                     PGA_Borderless,    TRUE,
  1912.  
  1913.                                     PGA_Visible,    1,
  1914.                                     PGA_Total,    1,
  1915.                                 TAG_DONE)) != NULL)
  1916.                                 {
  1917.                                     if((xdev -> gadget[HORIZONTAL_SCROLLER] = NewObject(NULL,"propgclass",
  1918.                                         GA_ID,        HORIZONTAL_SCROLLER,
  1919.                                         GA_Previous,    xdev -> gadget[VERTICAL_SCROLLER],
  1920.  
  1921.                                         GA_Height,    SizeHeight - 4,
  1922.                                         GA_RelBottom,    -(SizeHeight - 4 + 1),
  1923.                                         GA_Left,    4,
  1924.                                         GA_RelWidth,    -(2 + SizeWidth + 4 + 2 * ArrowWidth),
  1925.  
  1926.                                         GA_GZZGadget,    TRUE,
  1927.                                         GA_Immediate,    TRUE,
  1928.                                         GA_FollowMouse,    TRUE,
  1929.                                         GA_RelVerify,    TRUE,
  1930.                                         GA_BottomBorder,TRUE,
  1931.  
  1932.                                         PGA_Freedom,    FREEHORIZ,
  1933.                                         PGA_NewLook,    TRUE,
  1934.                                         PGA_Borderless,    TRUE,
  1935.  
  1936.                                         PGA_Visible,    1,
  1937.                                         PGA_Total,    1,
  1938.                                     TAG_DONE)) != NULL)
  1939.                                     {
  1940.                                         STATIC struct TagItem ArrowMappings[] = { GA_ID, GA_ID, TAG_END };
  1941.  
  1942.                                         if((xdev -> gadget[UP_ARROW] = NewObject(NULL,"buttongclass",
  1943.                                             GA_ID,        UP_ARROW,
  1944.                                             GA_Previous,    xdev -> gadget[HORIZONTAL_SCROLLER],
  1945.  
  1946.                                             GA_GZZGadget,    TRUE,
  1947.                                             GA_Image,    xdev -> image[UP_IMAGE],
  1948.                                             GA_RelRight,    -(SizeWidth - 1),
  1949.                                             GA_RelBottom,    -(SizeHeight - 1 + 2 * ArrowHeight),
  1950.                                             GA_Height,    ArrowHeight,
  1951.                                             GA_Width,    SizeWidth,
  1952.                                             GA_Immediate,    TRUE,
  1953.                                             GA_RelVerify,    TRUE,
  1954.                                             GA_RightBorder,    TRUE,
  1955.  
  1956.                                             ICA_TARGET,    ICTARGET_IDCMP,
  1957.                                             ICA_MAP,    ArrowMappings,
  1958.                                         TAG_DONE)) != NULL)
  1959.                                         {
  1960.                                             if((xdev -> gadget[DOWN_ARROW] = NewObject(NULL,"buttongclass",
  1961.                                                 GA_ID,        DOWN_ARROW,
  1962.                                                 GA_Previous,    xdev -> gadget[UP_ARROW],
  1963.  
  1964.                                                 GA_GZZGadget,    TRUE,
  1965.                                                 GA_Image,    xdev -> image[DOWN_IMAGE],
  1966.                                                 GA_RelRight,    -(SizeWidth - 1),
  1967.                                                 GA_RelBottom,    -(SizeHeight - 1 + ArrowHeight),
  1968.                                                 GA_Height,    ArrowHeight,
  1969.                                                 GA_Width,    SizeWidth,
  1970.                                                 GA_Immediate,    TRUE,
  1971.                                                 GA_RelVerify,    TRUE,
  1972.                                                 GA_RightBorder,    TRUE,
  1973.  
  1974.                                                 ICA_TARGET,    ICTARGET_IDCMP,
  1975.                                                 ICA_MAP,    ArrowMappings,
  1976.                                             TAG_DONE)) != NULL)
  1977.                                             {
  1978.                                                 if((xdev -> gadget[LEFT_ARROW] = NewObject(NULL,"buttongclass",
  1979.                                                     GA_ID,        LEFT_ARROW,
  1980.                                                     GA_Previous,    xdev -> gadget[DOWN_ARROW],
  1981.  
  1982.                                                     GA_GZZGadget,    TRUE,
  1983.                                                     GA_Image,    xdev -> image[LEFT_IMAGE],
  1984.                                                     GA_RelRight,    -(SizeWidth - 1 + 2 * ArrowWidth),
  1985.                                                     GA_RelBottom,    -(SizeHeight - 1),
  1986.                                                     GA_Height,    SizeHeight,
  1987.                                                     GA_Width,    ArrowWidth,
  1988.                                                     GA_Immediate,    TRUE,
  1989.                                                     GA_RelVerify,    TRUE,
  1990.                                                     GA_BottomBorder,TRUE,
  1991.  
  1992.                                                     ICA_TARGET,    ICTARGET_IDCMP,
  1993.                                                     ICA_MAP,    ArrowMappings,
  1994.                                                 TAG_DONE)) != NULL)
  1995.                                                 {
  1996.                                                     if((xdev -> gadget[RIGHT_ARROW] = NewObject(NULL,"buttongclass",
  1997.                                                         GA_ID,        RIGHT_ARROW,
  1998.                                                         GA_Previous,    xdev -> gadget[LEFT_ARROW],
  1999.  
  2000.                                                         GA_GZZGadget,    TRUE,
  2001.                                                         GA_Image,    xdev -> image[RIGHT_IMAGE],
  2002.                                                         GA_RelRight,    -(SizeWidth - 1 + ArrowWidth),
  2003.                                                         GA_RelBottom,    -(SizeHeight - 1),
  2004.                                                         GA_Height,    SizeHeight,
  2005.                                                         GA_Width,    ArrowWidth,
  2006.                                                         GA_Immediate,    TRUE,
  2007.                                                         GA_RelVerify,    TRUE,
  2008.                                                         GA_BottomBorder,TRUE,
  2009.  
  2010.                                                         ICA_TARGET,    ICTARGET_IDCMP,
  2011.                                                         ICA_MAP,    ArrowMappings,
  2012.                                                     TAG_DONE)) != NULL)
  2013.                                                         Result = TRUE;
  2014.                                                 }
  2015.                                             }
  2016.                                         }
  2017.                                     }
  2018.                                 }
  2019.                             }
  2020.                         }
  2021.                     }
  2022.                 }
  2023.  
  2024.                 FreeScreenDrawInfo(Screen,DrawInfo);
  2025.             }
  2026.         }
  2027.     }
  2028.  
  2029.     return(Result);
  2030. }
  2031.  
  2032.     /* WindowResize(gx_device *dev):
  2033.      *
  2034.      *    Update the slider sizes and positions after the window
  2035.      *    was resized.
  2036.      */
  2037.  
  2038. VOID
  2039. WindowResize(gx_device *dev)
  2040. {
  2041.     LONG    DeltaX,
  2042.         DeltaY,
  2043.         Temp;
  2044.  
  2045.         /* Query the current horizontal slider position. */
  2046.  
  2047.     if((Temp = LAYERXOFFSET(xdev -> window) + xdev -> window -> GZZWidth) > xdev -> super_width)
  2048.         DeltaX = xdev -> super_width - Temp;
  2049.     else
  2050.         DeltaX = 0;
  2051.  
  2052.         /* Query the current vertical slider position. */
  2053.  
  2054.     if((Temp = LAYERYOFFSET(xdev -> window) + xdev -> window -> GZZHeight) > xdev -> super_height)
  2055.         DeltaY = xdev -> super_height - Temp;
  2056.     else
  2057.         DeltaY = 0;
  2058.  
  2059.         /* Move the currently displayed window area around. */
  2060.  
  2061.     if(DeltaX || DeltaY)
  2062.         ScrollLayer(NULL,xdev -> window -> RPort -> Layer,DeltaX,DeltaY);
  2063.  
  2064.         /* Update the new horizontal slider position and size. */
  2065.  
  2066.     SetGadgetAttrs(xdev -> gadget[HORIZONTAL_SCROLLER],xdev -> window,NULL,
  2067.         PGA_Top,    LAYERXOFFSET(xdev -> window),
  2068.         PGA_Visible,    xdev -> window -> GZZWidth,
  2069.         PGA_Total,    xdev -> super_width,
  2070.     TAG_DONE);
  2071.  
  2072.         /* Update the new vertical slider position and size. */
  2073.  
  2074.     SetGadgetAttrs(xdev -> gadget[VERTICAL_SCROLLER],xdev -> window,NULL,
  2075.         PGA_Top,    LAYERYOFFSET(xdev -> window),
  2076.         PGA_Visible,    xdev -> window -> GZZHeight,
  2077.         PGA_Total,    xdev -> super_height,
  2078.     TAG_DONE);
  2079. }
  2080.  
  2081.     /* WindowUpdate(struct Gadget *Gadget,gx_device *dev):
  2082.      *
  2083.      *    Move the currently visible portion of the
  2084.      *    window according to the current slider
  2085.      *    position.
  2086.      */
  2087.  
  2088. VOID
  2089. WindowUpdate(struct Gadget *Gadget,gx_device *dev)
  2090. {
  2091.     LONG Storage;
  2092.  
  2093.     switch(Gadget -> GadgetID)
  2094.     {
  2095.         case HORIZONTAL_SCROLLER:
  2096.  
  2097.             if(GetAttr(PGA_Top,Gadget,&Storage))
  2098.                 ScrollLayer(NULL,xdev -> window -> RPort -> Layer,Storage - LAYERXOFFSET(xdev -> window),0);
  2099.  
  2100.             break;
  2101.  
  2102.         case VERTICAL_SCROLLER:
  2103.  
  2104.             if(GetAttr(PGA_Top,Gadget,&Storage))
  2105.                 ScrollLayer(NULL,xdev -> window -> RPort -> Layer,0,Storage - LAYERYOFFSET(xdev -> window));
  2106.  
  2107.             break;
  2108.     }
  2109. }
  2110.  
  2111.     /* MoveAround(struct Gadget *Gadget,int How,gx_device *dev):
  2112.      *
  2113.      *    Move the currently visible window area according to
  2114.      *    user input.
  2115.      */
  2116.  
  2117. VOID
  2118. MoveAround(struct Gadget *Gadget,LONG How,gx_device *dev)
  2119. {
  2120.     LONG Storage;
  2121.  
  2122.     if(GetAttr(PGA_Top,Gadget,&Storage))
  2123.     {
  2124.         LONG Max;
  2125.  
  2126.         switch(Gadget -> GadgetID)
  2127.         {
  2128.             case HORIZONTAL_SCROLLER:
  2129.  
  2130.                 Max = xdev -> super_width - xdev -> window -> GZZWidth;
  2131.                 break;
  2132.  
  2133.             case VERTICAL_SCROLLER:
  2134.  
  2135.                 Max = xdev -> super_height - xdev -> window -> GZZHeight;
  2136.                 break;
  2137.         }
  2138.  
  2139.         switch(How)
  2140.         {
  2141.             case MOVE_MIN:
  2142.  
  2143.                 Storage = 0;
  2144.                 break;
  2145.  
  2146.             case MOVE_MAX:
  2147.  
  2148.                 Storage = Max;
  2149.                 break;
  2150.  
  2151.             case MOVE_DOWN:
  2152.  
  2153.                 if(Storage > xdev -> super_height / 100)
  2154.                     Storage -= xdev -> super_height / 100;
  2155.                 else
  2156.                     Storage = 0;
  2157.  
  2158.                 break;
  2159.  
  2160.             case MOVE_FAR_DOWN:
  2161.  
  2162.                 if(Storage > xdev -> super_height / 10)
  2163.                     Storage -= xdev -> super_height / 10;
  2164.                 else
  2165.                     Storage = 0;
  2166.  
  2167.                 break;
  2168.  
  2169.             case MOVE_FAR_UP:
  2170.  
  2171.                 if(Storage + xdev -> super_width / 10 < Max)
  2172.                     Storage += xdev -> super_width / 10;
  2173.                 else
  2174.                     Storage = Max;
  2175.  
  2176.                 break;
  2177.  
  2178.             case MOVE_UP:
  2179.  
  2180.                 if(Storage + xdev -> super_width / 100 < Max)
  2181.                     Storage += xdev -> super_width / 100;
  2182.                 else
  2183.                     Storage = Max;
  2184.  
  2185.                 break;
  2186.         }
  2187.  
  2188.         switch(Gadget -> GadgetID)
  2189.         {
  2190.             case HORIZONTAL_SCROLLER:
  2191.  
  2192.                 if(LAYERXOFFSET(xdev -> window) != Storage)
  2193.                 {
  2194.                     ScrollLayer(NULL,xdev -> window -> RPort -> Layer,Storage - LAYERXOFFSET(xdev -> window),0);
  2195.  
  2196.                     SetGadgetAttrs(Gadget,xdev -> window,NULL,
  2197.                         PGA_Top,Storage,
  2198.                     TAG_DONE);
  2199.                 }
  2200.  
  2201.                 break;
  2202.  
  2203.             case VERTICAL_SCROLLER:
  2204.  
  2205.                 if(LAYERYOFFSET(xdev -> window) != Storage)
  2206.                 {
  2207.                     ScrollLayer(NULL,xdev -> window -> RPort -> Layer,0,Storage - LAYERYOFFSET(xdev -> window));
  2208.  
  2209.                     SetGadgetAttrs(Gadget,xdev -> window,NULL,
  2210.                         PGA_Top,Storage,
  2211.                     TAG_DONE);
  2212.                 }
  2213.  
  2214.                 break;
  2215.         }
  2216.     }
  2217. }
  2218.  
  2219.     /* DispatchSuperWindow(gx_device *dev):
  2220.      *
  2221.      *    Dispatch user window input.
  2222.      */
  2223.  
  2224. VOID
  2225. DispatchSuperWindow(gx_device *dev)
  2226. {
  2227.     STATIC struct Gadget    *CurrentGadget = NULL;
  2228.  
  2229.     struct IntuiMessage    *IntuiMessage;
  2230.     ULONG             MsgClass,
  2231.                  MsgCode,
  2232.                  MsgQualifier;
  2233.     struct Gadget        *MsgGadget;
  2234.  
  2235.     while((IntuiMessage = (struct IntuiMessage *)GetMsg(xdev -> window -> UserPort)) != NULL)
  2236.     {
  2237.         MsgClass    = IntuiMessage -> Class;
  2238.         MsgCode        = IntuiMessage -> Code;
  2239.         MsgQualifier    = IntuiMessage -> Qualifier;
  2240.         MsgGadget    = IntuiMessage -> IAddress;
  2241.  
  2242.         ReplyMsg((struct Message *)IntuiMessage);
  2243.  
  2244.         switch(MsgClass)
  2245.         {
  2246.             case IDCMP_VANILLAKEY:
  2247.  
  2248.                 if(MsgCode == '\033' || MsgCode == '\003')
  2249.                     Signal((struct Task *)xdev -> main,SIG_KILL);
  2250.  
  2251.                 break;
  2252.  
  2253.             case IDCMP_RAWKEY:
  2254.  
  2255.                 switch(MsgCode)
  2256.                 {
  2257.                     case HELP_CODE:
  2258.  
  2259.                         DisplayBeep(xdev -> window -> WScreen);
  2260.  
  2261.                         break;
  2262.  
  2263.                     case CURSORUP:
  2264.  
  2265.                         if(MsgQualifier & IEQUALIFIER_CONTROL)
  2266.                             MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_MIN,dev);
  2267.                         else
  2268.                         {
  2269.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  2270.                                 MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_FAR_DOWN,dev);
  2271.                             else
  2272.                                 MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_DOWN,dev);
  2273.                         }
  2274.  
  2275.                         break;
  2276.  
  2277.                     case CURSORLEFT:
  2278.  
  2279.                         if(MsgQualifier & IEQUALIFIER_CONTROL)
  2280.                             MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_MIN,dev);
  2281.                         else
  2282.                         {
  2283.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  2284.                                 MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_FAR_DOWN,dev);
  2285.                             else
  2286.                                 MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_DOWN,dev);
  2287.                         }
  2288.  
  2289.                         break;
  2290.  
  2291.                     case CURSORRIGHT:
  2292.  
  2293.                         if(MsgQualifier & IEQUALIFIER_CONTROL)
  2294.                             MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_MAX,dev);
  2295.                         else
  2296.                         {
  2297.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  2298.                                 MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_FAR_UP,dev);
  2299.                             else
  2300.                                 MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_UP,dev);
  2301.                         }
  2302.  
  2303.                         break;
  2304.  
  2305.                     case CURSORDOWN:
  2306.  
  2307.                         if(MsgQualifier & IEQUALIFIER_CONTROL)
  2308.                             MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_MAX,dev);
  2309.                         else
  2310.                         {
  2311.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  2312.                                 MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_FAR_UP,dev);
  2313.                             else
  2314.                                 MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_UP,dev);
  2315.                         }
  2316.  
  2317.                         break;
  2318.  
  2319.                     default:
  2320.  
  2321.                         break;
  2322.                 }
  2323.  
  2324.                 break;
  2325.  
  2326.             case IDCMP_CLOSEWINDOW:
  2327.  
  2328.                 Signal((struct Task *)xdev -> main,SIG_KILL);
  2329.  
  2330.                 break;
  2331.  
  2332.             case IDCMP_GADGETDOWN:
  2333.  
  2334.                 CurrentGadget = MsgGadget;
  2335.  
  2336.                 WindowUpdate(MsgGadget,dev);
  2337.  
  2338.                 break;
  2339.  
  2340.             case IDCMP_GADGETUP:
  2341.  
  2342.                 CurrentGadget = NULL;
  2343.  
  2344.                 WindowUpdate(MsgGadget,dev);
  2345.  
  2346.                 break;
  2347.  
  2348.             case IDCMP_MOUSEMOVE:
  2349.  
  2350.                 if(CurrentGadget)
  2351.                     WindowUpdate(CurrentGadget,dev);
  2352.  
  2353.                 break;
  2354.  
  2355.             case IDCMP_IDCMPUPDATE:
  2356.  
  2357.                 switch(GetTagData(GA_ID,0,(struct TagItem *)MsgGadget))
  2358.                 {
  2359.                     case UP_ARROW:
  2360.  
  2361.                         MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_DOWN,dev);
  2362.                         break;
  2363.  
  2364.                     case DOWN_ARROW:
  2365.  
  2366.                         MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_UP,dev);
  2367.                         break;
  2368.  
  2369.                     case LEFT_ARROW:
  2370.  
  2371.                         MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_DOWN,dev);
  2372.                         break;
  2373.  
  2374.                     case RIGHT_ARROW:
  2375.  
  2376.                         MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_UP,dev);
  2377.                         break;
  2378.  
  2379.                     default:
  2380.  
  2381.                         break;
  2382.                 }
  2383.  
  2384.                 break;
  2385.  
  2386.             case IDCMP_NEWSIZE:
  2387.  
  2388.                 WindowResize(dev);
  2389.  
  2390.                 break;
  2391.  
  2392.             default:
  2393.  
  2394.                 break;
  2395.         }
  2396.     }
  2397. }
  2398.  
  2399.     /* Simple routine to call the cleanup routine of a device,
  2400.      * all devices are smart enough to handle shutdown in
  2401.      * case they have not been opened yet.
  2402.      */
  2403.  
  2404. STATIC void
  2405. close_device(gx_device_amiga *dev)
  2406. {
  2407.     if(xdev -> std_procs . close_device)
  2408.         (*xdev -> std_procs . close_device)((gx_device *)dev);
  2409. }
  2410.  
  2411.     /* devcleanup():
  2412.      *
  2413.      *    Clean up all devices, free all resources.
  2414.      */
  2415.  
  2416. void
  2417. devcleanup()
  2418. {
  2419.     close_device(&gs_amiga_device);
  2420.     close_device(&gs_amiga_low_device);
  2421.     close_device(&gs_amiga_high_device);
  2422.     close_device(&gs_amiga_super_device);
  2423.     close_device(&gs_amiga_a2024_device);
  2424.     close_device(&gs_amiga_picassoii_device);
  2425.     close_device(&gs_amiga_custom_device);
  2426.     close_device(&gs_amiga_printer_device);
  2427.     close_device(&gs_amiga_ilbm_device);
  2428. }
  2429.  
  2430.     /* amiga_set_pen(gx_device *dev,gx_color_index color):
  2431.      *
  2432.      *    Sets the rendering pen and remembers the current
  2433.      *    settings.
  2434.      */
  2435.  
  2436. STATIC VOID
  2437. amiga_set_pen(gx_device *dev,gx_color_index color)
  2438. {
  2439.     if(xdev -> last_pen != color)
  2440.         SetAPen(xdev -> rport,xdev -> last_pen = color);
  2441. }
  2442.  
  2443.     /* amiga_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue):
  2444.      *
  2445.      *    Map a colour either to the black or the light rendering pen.
  2446.      */
  2447.  
  2448. gx_color_index
  2449. amiga_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue)
  2450. {
  2451.     if((red | green | blue) > gx_max_color_value / 2)
  2452.         return(LightPen);
  2453.     else
  2454.         return(DarkPen);
  2455. }
  2456.  
  2457.     /* amiga_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3]):
  2458.      *
  2459.      *    Map the light/dark rendering pen to RGB values.
  2460.      */
  2461.  
  2462. int
  2463. amiga_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3])
  2464. {
  2465.     int i;
  2466.  
  2467.     if(color == LightPen)
  2468.     {
  2469.         for(i = 0 ; i < 3 ; i++)
  2470.             rgb[i] = gx_max_color_value;
  2471.     }
  2472.     else
  2473.     {
  2474.         for(i = 0 ; i < 3 ; i++)
  2475.             rgb[i] = 0;
  2476.     }
  2477.  
  2478.     return(0);
  2479. }
  2480.  
  2481.     /* AllocatePens(struct ViewPort *VPort,LONG CubeSize):
  2482.      *
  2483.      *    Allocate shareable viewport pens.
  2484.      */
  2485.  
  2486. LONG *
  2487. AllocatePens(struct ViewPort *VPort,LONG CubeSize)
  2488. {
  2489.     if(GfxBase -> LibNode . lib_Version >= 39)
  2490.     {
  2491.         LONG Total = CubeSize * CubeSize * CubeSize,*Pens;
  2492.  
  2493.         if((Pens = (LONG *)AllocVec(sizeof(LONG) * Total,MEMF_ANY)) != NULL)
  2494.         {
  2495.             LONG i,r,g,b,max = CubeSize - 1;
  2496.  
  2497.             for(i = 0 ; i < Total ; i++)
  2498.                 Pens[i] = -1;
  2499.  
  2500.             i = 0;
  2501.  
  2502.             for(r = 0 ; r < CubeSize ; r++)
  2503.             {
  2504.                 for(g = 0 ; g < CubeSize ; g++)
  2505.                 {
  2506.                     for(b = 0 ; b < CubeSize ; b++)
  2507.                     {
  2508.                         if((Pens[i++] = ObtainBestPen(VPort -> ColorMap,SPREAD((255 * r) / max),SPREAD((255 * g) / max),SPREAD((255 * b) / max),
  2509.                             OBP_FailIfBad,    TRUE,
  2510.                             OBP_Precision,    PRECISION_IMAGE,
  2511.                         TAG_DONE)) == -1)
  2512.                         {
  2513.                             FreeVec(Pens);
  2514.  
  2515.                             return(NULL);
  2516.                         }
  2517.                     }
  2518.                 }
  2519.             }
  2520.  
  2521.             return(Pens);
  2522.         }
  2523.     }
  2524.  
  2525.     return(NULL);
  2526. }
  2527.  
  2528.     /* amiga_open_default(gx_device *dev):
  2529.      *
  2530.      *    Open the default device, i.e. a window on the Workbench screen.
  2531.      */
  2532.  
  2533. int
  2534. amiga_open_default(gx_device *dev)
  2535. {
  2536.     struct Screen *DefaultScreen;
  2537.  
  2538.         /* Get a lock on the default public screen. */
  2539.  
  2540.     if((DefaultScreen = LockPubScreen(NULL)) != NULL)
  2541.     {
  2542.         struct DisplayInfo    DisplayInfo;
  2543.         ULONG             Mode;
  2544.  
  2545.             /* Get the default public screen display mode. */
  2546.  
  2547.         Mode = GetVPModeID(&DefaultScreen -> ViewPort);
  2548.  
  2549.             /* Inquire display mode information. */
  2550.  
  2551.         if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,Mode))
  2552.         {
  2553.             LONG    ScreenWidth,
  2554.                 ScreenHeight;
  2555.             LONG    i;
  2556.             double    Width,
  2557.                 Height;
  2558.             LONG    Depth;
  2559.  
  2560.             if(GfxBase -> LibNode . lib_Version >= 39)
  2561.                 Depth = GetBitMapAttr(DefaultScreen -> RastPort . BitMap,BMA_DEPTH);
  2562.             else
  2563.                 Depth = DefaultScreen -> RastPort . BitMap -> Depth;
  2564.  
  2565.                 /* Determine screen view dimensions. */
  2566.  
  2567.             if(DefaultScreen -> ViewPort . ColorMap -> cm_vpe)
  2568.             {
  2569.                 struct ViewPortExtra *Extra = DefaultScreen -> ViewPort . ColorMap -> cm_vpe;
  2570.  
  2571.                 ScreenWidth    = Extra -> DisplayClip . MaxX - Extra -> DisplayClip . MinX + 1;
  2572.                 ScreenHeight    = Extra -> DisplayClip . MaxY - Extra -> DisplayClip . MinY + 1;
  2573.             }
  2574.             else
  2575.             {
  2576.                 struct ViewPortExtra *Extra;
  2577.  
  2578.                 if((Extra = (struct ViewPortExtra *)GfxLookUp(&DefaultScreen -> ViewPort)) != NULL)
  2579.                 {
  2580.                     ScreenWidth    = Extra -> DisplayClip . MaxX - Extra -> DisplayClip . MinX + 1;
  2581.                     ScreenHeight    = Extra -> DisplayClip . MaxY - Extra -> DisplayClip . MinY + 1;
  2582.                 }
  2583.                 else
  2584.                 {
  2585.                     ScreenWidth    = DefaultScreen -> Width;
  2586.                     ScreenHeight    = DefaultScreen -> Height;
  2587.                 }
  2588.             }
  2589.  
  2590.                 /* Use the best guess, we will take the standard
  2591.                  * low resolution x-dpi value and scale it by
  2592.                  * the pixel speed.
  2593.                  */
  2594. /* JOOP: terrible kludge to filter Amiga modes from GFXcard modes */
  2595. /*       which don't always set a nice PixelSpeed (Merlin) */
  2596.             if(DisplayInfo.PixelSpeed==35 || DisplayInfo.PixelSpeed==70 || DisplayInfo.PixelSpeed==140)
  2597.             {
  2598.                 xdev -> x_pixels_per_inch = (35.0 * 140.0) / (double)DisplayInfo . PixelSpeed;
  2599.                 xdev -> y_pixels_per_inch = (xdev -> x_pixels_per_inch * (double)DisplayInfo . Resolution . x) / (double)DisplayInfo . Resolution . y;
  2600.             }
  2601.             else
  2602.             {
  2603.                 xdev -> x_pixels_per_inch = 72.27;
  2604.                 xdev -> y_pixels_per_inch = 72.27;
  2605.             }
  2606.  
  2607.             if(xdev -> width > 0 && xdev -> height > 0)
  2608.             {
  2609.                 xdev -> super_width    = xdev -> width;
  2610.                 xdev -> super_height    = xdev -> height;
  2611.             }
  2612.             else
  2613.             {
  2614.                 if(xdev -> page_width > 0.0)
  2615.                     xdev -> super_width = (LONG)(xdev -> page_width * xdev -> x_pixels_per_inch);
  2616.                 else
  2617.                     xdev -> super_width = 640;
  2618.  
  2619.                 if(xdev -> page_height > 0.0)
  2620.                     xdev -> super_height = (LONG)(xdev -> page_height * xdev -> y_pixels_per_inch);
  2621.                 else
  2622.                     xdev -> super_height = 512;
  2623.             }
  2624.  
  2625.                 /* Allocate a bitmap ready to be used for
  2626.                  * rendering.
  2627.                  */
  2628.  
  2629.             if((xdev -> super_bitmap = CreateBitMap(xdev -> super_width,xdev -> super_height,Depth,BMF_DISPLAYABLE,DefaultScreen -> RastPort . BitMap,FALSE)) != NULL)
  2630.             {
  2631.                     /* Clear the bitplanes. */
  2632.  
  2633.                 BltBitMap(xdev -> super_bitmap,0,0,xdev -> super_bitmap,0,0,xdev -> super_width,xdev -> super_height,0x00,(1 << xdev -> super_bitmap -> Depth) - 1,NULL);
  2634.  
  2635.                     /* Create the scroller handles. */
  2636.  
  2637.                 if(CreateScrollers(dev,DefaultScreen))
  2638.                 {
  2639.                     struct IBox ZoomBox;
  2640.  
  2641.                         /* Set up the window alternate
  2642.                          * position.
  2643.                          */
  2644.  
  2645.                     ZoomBox . Left        = 0;
  2646.                     ZoomBox . Top        = DefaultScreen -> BarHeight + 1;
  2647.                     ZoomBox . Width        = ScreenWidth;
  2648.                     ZoomBox . Height    = ScreenHeight - ZoomBox . Top;
  2649.  
  2650.                         /* Eventually, open the display window. */
  2651.  
  2652.                     if((xdev -> window = OpenWindowTags(NULL,
  2653.                         WA_InnerWidth,        MIN(DefaultScreen -> Width / 2,xdev -> super_width),
  2654.                         WA_InnerHeight,        MIN(DefaultScreen -> Height / 2,xdev -> super_height),
  2655.                         WA_CloseGadget,        TRUE,
  2656.                         WA_DepthGadget,        TRUE,
  2657.                         WA_SizeGadget,        TRUE,
  2658.                         WA_SizeBRight,        TRUE,
  2659.                         WA_SizeBBottom,        TRUE,
  2660.                         WA_Zoom,        &ZoomBox,
  2661.                         WA_DragBar,        TRUE,
  2662.                         WA_NoCareRefresh,    TRUE,
  2663.                         WA_GimmeZeroZero,    TRUE,
  2664.                         WA_RMBTrap,        TRUE,
  2665.                         WA_SuperBitMap,        xdev -> super_bitmap,
  2666.                         WA_Gadgets,        xdev -> gadget[VERTICAL_SCROLLER],
  2667.                         WA_CustomScreen,    DefaultScreen,
  2668.                         WA_Title,        "Ghostscript Amiga output window",
  2669.                     TAG_DONE)) != NULL)
  2670.                     {
  2671.                         if((xdev -> temp_rport = CreateTempRPort(xdev -> window -> RPort)) != NULL)
  2672.                         {
  2673.                             if((xdev -> temp_array = (UBYTE *)AllocVec((xdev -> window -> WScreen -> Width + 15) & ~15,MEMF_ANY)) != NULL)
  2674.                             {
  2675.                                 const sigset_t trapped = sigmask(SIGINT);
  2676.  
  2677.                                 struct Task *Task;
  2678.  
  2679.                                     /* Don't let anybody interrupt us! */
  2680. #ifdef IXEMUL
  2681.                                 sigprocmask(SIG_BLOCK,&trapped,NULL);
  2682. #endif
  2683.                                     /* Bring the window dispatcher task
  2684.                                      * to life...
  2685.                                      */
  2686.  
  2687.                                 Forbid();
  2688.  
  2689.                                 if((Task = (struct Task *)CreateTask("Ghostscript window dispatcher",5,DispatchTask,8192)) != NULL)
  2690.                                 {
  2691.                                         /* Cheap... */
  2692.  
  2693.                                     Task -> tc_UserData = dev;
  2694.  
  2695.                                         /* Who's calling? */
  2696.  
  2697.                                     xdev -> main = (struct Process *)FindTask(NULL);
  2698.  
  2699.                                         /* Clear the handshake bit. */
  2700.  
  2701.                                     SetSignal(0,SIG_HANDSHAKE);
  2702.  
  2703.                                         /* Wake the task up. */
  2704.  
  2705.                                     Signal(Task,SIG_WAKEUP);
  2706.  
  2707.                                         /* Wait for the report. */
  2708.  
  2709.                                     Wait(SIG_HANDSHAKE);
  2710.  
  2711.                                         /* Get the result. */
  2712.  
  2713.                                     Task = xdev -> dispatcher;
  2714.                                 }
  2715.  
  2716.                                 Permit();
  2717.  
  2718.                                     /* Unblock signals. */
  2719. #ifdef IXEMUL
  2720.                                 sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  2721. #endif
  2722.                                     /* Did we succeed in creating
  2723.                                      * the dispatcher task?
  2724.                                      */
  2725.  
  2726.                                 if(Task)
  2727.                                 {
  2728.                                     UWORD    MaxValue = 0,
  2729.                                         MinValue = 15000,
  2730.                                         Value,
  2731.                                         R,G,B;
  2732.  
  2733.                                         /* Set the window limits. */
  2734.  
  2735.                                     WindowLimits(xdev -> window,xdev -> window -> BorderLeft + MINIMUM_WIDTH + xdev -> window -> BorderRight,xdev -> window -> BorderTop + MINIMUM_HEIGHT + xdev -> window -> BorderBottom,xdev -> window -> BorderLeft + xdev -> super_width + xdev -> window -> BorderRight,xdev -> window -> BorderTop + xdev -> super_height + xdev -> window -> BorderBottom);
  2736.  
  2737.                                         /* Update the sliders. */
  2738.  
  2739.                                     WindowResize(dev);
  2740.  
  2741.                                         /* Look for the darkest and the lightest screen colours. */
  2742.  
  2743.                                     for(i = 0 ; i < MIN(xdev -> window -> WScreen -> ViewPort . ColorMap -> Count,(1 << Depth)) ; i++)
  2744.                                     {
  2745.                                         Value = GetRGB4(xdev -> window -> WScreen -> ViewPort . ColorMap,i);
  2746.  
  2747.                                         R = (Value >> 8) & 0xF;
  2748.                                         G = (Value >> 4) & 0xF;
  2749.                                         B =  Value       & 0xF;
  2750.  
  2751.                                             /* Luminance conversion included */
  2752.  
  2753.                                         Value = R * 299 + G * 588 + B * 113;
  2754.  
  2755.                                         if(Value > MaxValue)
  2756.                                         {
  2757.                                             MaxValue = Value;
  2758.  
  2759.                                             LightPen = i;
  2760.                                         }
  2761.  
  2762.                                         if(Value < MinValue)
  2763.                                         {
  2764.                                             MinValue = Value;
  2765.  
  2766.                                             DarkPen = i;
  2767.                                         }
  2768.                                     }
  2769.  
  2770.                                         /* Fill in the rest. */
  2771.  
  2772.                                     xdev -> width    = xdev -> super_width;
  2773.                                     xdev -> height    = xdev -> super_height;
  2774.                                     xdev -> rport    = xdev -> window -> RPort;
  2775.  
  2776.                                         /* Does the display support
  2777.                                          * at least eight colours?
  2778.                                          */
  2779.  
  2780.                                     if(Depth >= 3)
  2781.                                     {
  2782.                                         LONG cube_size,max;
  2783.  
  2784.                                             /* Set up a fitting colour cube. */
  2785.  
  2786.                                         for(cube_size = 6 ; cube_size >= 2 ; cube_size--)
  2787.                                         {
  2788.                                             if((max = cube_size * cube_size * cube_size) <= 1 << Depth)
  2789.                                                 break;
  2790.                                         }
  2791.  
  2792.                                             /* Got enough colours? */
  2793.  
  2794.                                         if(cube_size != 1)
  2795.                                         {
  2796.                                             LONG *Pens;
  2797.  
  2798.                                                 /* Try to grab the cube colours,
  2799.                                                  * making a colour display.
  2800.                                                  */
  2801.  
  2802.                                             if(Pens = AllocatePens(&xdev -> window -> WScreen -> ViewPort,cube_size))
  2803.                                                 set_colour_device((gx_device_amiga *)dev,cube_size,Pens);
  2804.                                         }
  2805.                                     }
  2806.  
  2807.                                     SetBPen(xdev -> rport,0);
  2808.                                     SetDrMd(xdev -> rport,JAM2);
  2809.  
  2810.                                     amiga_set_pen(dev,DarkPen);
  2811.  
  2812.                                     UnlockPubScreen(NULL,DefaultScreen);
  2813.  
  2814.                                     return(0);
  2815.                                 }
  2816.                                 else
  2817.                                     perror("Ghostscript: failed to create dispatcher task");
  2818.                             }
  2819.                             else
  2820.                                 perror("Ghostscript: failed to create temporary line buffer.");
  2821.                         }
  2822.                         else
  2823.                             perror("Ghostscript: failed to create temporary raster port");
  2824.                     }
  2825.                     else
  2826.                         perror("Ghostscript: failed to open window");
  2827.                 }
  2828.                 else
  2829.                     perror("Ghostscript: failed to allocate scrollers");
  2830.             }
  2831.             else
  2832.                 perror("Ghostscript: failed to allocate bitmap");
  2833.         }
  2834.         else
  2835.             perror("Ghostscript: failed to get display mode information");
  2836.  
  2837.         UnlockPubScreen(NULL,DefaultScreen);
  2838.     }
  2839.     else
  2840.         perror("Ghostscript: failed to lock default public screen");
  2841.  
  2842.     return(-1);
  2843. }
  2844.  
  2845.     /* amiga_open_low(gx_device *dev):
  2846.      *
  2847.      *    Open the low resolution device.
  2848.      */
  2849.  
  2850. int
  2851. amiga_open_low(gx_device *dev)
  2852. {
  2853.     return(amiga_open(dev,LORES_KEY));
  2854. }
  2855.  
  2856.     /* amiga_open_high(gx_device *dev):
  2857.      *
  2858.      *    Open the high resolution device.
  2859.      */
  2860.  
  2861. int
  2862. amiga_open_high(gx_device *dev)
  2863. {
  2864.     return(amiga_open(dev,HIRESLACE_KEY));
  2865. }
  2866.  
  2867.     /* amiga_open_super(gx_device *dev):
  2868.      *
  2869.      *    Open the super high resolution device.
  2870.      */
  2871.  
  2872. int
  2873. amiga_open_super(gx_device *dev)
  2874. {
  2875.         /* Fall back to the default if not available. */
  2876.  
  2877.     if(ModeNotAvailable(SUPERLACE_KEY))
  2878.         return(amiga_open_high(dev));
  2879.     else
  2880.         return(amiga_open(dev,SUPERLACE_KEY));
  2881. }
  2882.  
  2883.     /* amiga_open_a2024(gx_device *dev):
  2884.      *
  2885.      *    Open the A2024 device.
  2886.      */
  2887.  
  2888. int
  2889. amiga_open_a2024(gx_device *dev)
  2890. {
  2891.         /* Fall back to the default if not available. */
  2892.  
  2893.     if(ModeNotAvailable(A2024TENHERTZ_KEY))
  2894.         return(amiga_open_super(dev));
  2895.     else
  2896.         return(amiga_open(dev,A2024TENHERTZ_KEY));
  2897. }
  2898.  
  2899.     /* amiga_open_picassoii(gx_device *dev):
  2900.      *
  2901.      *    Open the Picasso II device.
  2902.      */
  2903.  
  2904. int
  2905. amiga_open_picassoii(gx_device *dev)
  2906. {
  2907.         /* Fall back to the default if not available. */
  2908.  
  2909.     if(ModeNotAvailable(0x40020002))
  2910.         return(amiga_open_super(dev));
  2911.     else
  2912.         return(amiga_open(dev,0x40020002));
  2913. }
  2914.  
  2915. int
  2916. amiga_open_custom(gx_device *dev)
  2917. {
  2918.     UBYTE    Buffer[256];
  2919.     ULONG    ScreenID    = INVALID_ID;
  2920.     BOOL    DontTouch    = FALSE;
  2921.  
  2922.         /* First step: check for an environment variable to give
  2923.          *             the name of the display mode to use.
  2924.          */
  2925.  
  2926.     if(GetVar("GSCUSTOMMODE",Buffer,256,NULL) != -1)
  2927.     {
  2928.         UBYTE PatternBuffer[516];
  2929.  
  2930.             /* Set up the search pattern. */
  2931.  
  2932.         if(ParsePatternNoCase(Buffer,PatternBuffer,516) >= 0)
  2933.         {
  2934.             ULONG CurrentID = INVALID_ID,ID;
  2935.  
  2936.                 /* Scan the entire list. */
  2937.  
  2938.             while((CurrentID = NextDisplayInfo(CurrentID)) != INVALID_ID)
  2939.             {
  2940.                     /* Valid mode? */
  2941.  
  2942.                 if(!ModeNotAvailable(CurrentID))
  2943.                 {
  2944.                     struct NameInfo    NameInfo;
  2945.  
  2946.                         /* Get the name information. */
  2947.  
  2948.                     if(GetDisplayInfoData(NULL,&NameInfo,sizeof(struct NameInfo),DTAG_NAME,CurrentID))
  2949.                     {
  2950.                             /* Does the mode name match the pattern given? */
  2951.  
  2952.                         if(MatchPatternNoCase(PatternBuffer,NameInfo . Name))
  2953.                         {
  2954.                             ScreenID = CurrentID;
  2955.  
  2956.                                 /* Don't overwrite the variable contents. */
  2957.  
  2958.                             DontTouch = TRUE;
  2959.  
  2960.                             break;
  2961.                         }
  2962.                     }
  2963.                 }
  2964.             }
  2965.         }
  2966.     }
  2967.  
  2968.     if(ScreenID == INVALID_ID && AslBase)
  2969.     {
  2970.         struct ScreenModeRequester *ScreenModeRequester;
  2971.  
  2972.         if((ScreenModeRequester = (struct ScreenModeRequester *)AllocAslRequestTags(ASL_ScreenModeRequest,TAG_DONE)) != NULL)
  2973.         {
  2974.             if(AslRequestTags(ScreenModeRequester,
  2975.                 ASLSM_TitleText,    "Select GhostScript screen display mode",
  2976.                 ASLSM_MinDepth,        1,
  2977.                 ASLSM_MaxDepth,        8,
  2978.             TAG_DONE))
  2979.                 ScreenID = ScreenModeRequester -> sm_DisplayID;
  2980.  
  2981.             FreeAslRequest(ScreenModeRequester);
  2982.         }
  2983.     }
  2984.  
  2985.         /* Fall back to the default if not available. */
  2986.  
  2987.     if(ModeNotAvailable(ScreenID))
  2988.         return(amiga_open_default(dev));
  2989.     else
  2990.     {
  2991.         int result = amiga_open(dev,ScreenID);
  2992.  
  2993.             /* If successful store the name of the
  2994.              * screen mode selected.
  2995.              */
  2996.  
  2997.         if(!result && !DontTouch)
  2998.         {
  2999.             struct NameInfo    NameInfo;
  3000.  
  3001.             if(GetDisplayInfoData(NULL,&NameInfo,sizeof(struct NameInfo),DTAG_NAME,ScreenID))
  3002.                 SetVar("GSCUSTOMMODE",NameInfo . Name,-1,NULL);
  3003.         }
  3004.  
  3005.         return(result);
  3006.     }
  3007. }
  3008.  
  3009.     /* amiga_open_printer(gx_device *dev):
  3010.      *
  3011.      *    Open the printer device.
  3012.      */
  3013.  
  3014. int
  3015. amiga_open_printer(gx_device *dev)
  3016. {
  3017.     if((xdev -> port = CreateMsgPort()) != NULL)
  3018.     {
  3019.         if((xdev -> printer = (struct IODRPReq *)CreateIORequest(xdev -> port,sizeof(struct IODRPReq))) != NULL)
  3020.         {
  3021.             if(!OpenDevice("printer.device",0,(struct IORequest *)xdev -> printer,0))
  3022.             {
  3023.                 if((xdev -> rport = (struct RastPort *)AllocVec(sizeof(struct RastPort),MEMF_ANY)) != NULL)
  3024.                 {
  3025.                     const sigset_t    trapped = sigmask(SIGINT);
  3026.                     struct BitMap    DummyBitMap;
  3027.                     UWORD        DummyLine[12];
  3028.  
  3029.                     InitRastPort(xdev -> rport);
  3030.  
  3031.                         /* Cook up a dummy bitmap to keep
  3032.                          * `smart' drivers from complaining.
  3033.                          */
  3034.  
  3035.                     InitBitMap(&DummyBitMap,12,16,16);
  3036.  
  3037.                     DummyBitMap . Planes[0] = (PLANEPTR)&DummyLine;
  3038.  
  3039.                     xdev -> rport -> BitMap = &DummyBitMap;
  3040.  
  3041.                         /* Query page size requirements. */
  3042.  
  3043.                     xdev -> printer -> io_Command    = PRD_DUMPRPORT;
  3044.                     xdev -> printer -> io_RastPort    = xdev -> rport;
  3045.                     xdev -> printer -> io_SrcWidth    = 16;
  3046.                     xdev -> printer -> io_SrcHeight    = 16;
  3047.                     xdev -> printer -> io_Modes    = LORES_KEY;
  3048.  
  3049.                     xdev -> printer -> io_Special    |= SPECIAL_FULLCOLS | SPECIAL_FULLROWS | SPECIAL_NOPRINT;
  3050.  
  3051.                         /* Don't let them stop us now! */
  3052. #ifdef IXEMUL
  3053.                     sigprocmask(SIG_BLOCK,&trapped,NULL);
  3054. #endif
  3055.                         /* Ask for it... */
  3056.  
  3057.                     if(!DoIO((struct IORequest *)xdev -> printer))
  3058.                     {
  3059.                         struct PrinterExtendedData    *PED;
  3060.                         struct PrinterData        *PD;
  3061.                         struct Preferences        *Prefs;
  3062.                         LONG                 Depth,
  3063.                                          NumColours,
  3064.                                          CubeSize;
  3065.                         LONG                 PageWidth,
  3066.                                          PageHeight;
  3067.  
  3068.                             /* Unblock ^C signal. */
  3069. #ifdef IXEMUL
  3070.                         sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  3071. #endif
  3072.                         xdev -> printer -> io_Special &= ~(SPECIAL_FULLCOLS | SPECIAL_FULLROWS | SPECIAL_NOPRINT);
  3073.  
  3074.                             /* Get the printer internal data. */
  3075.  
  3076.                         PD    = (struct PrinterData *)xdev -> printer -> io_Device;
  3077.                         PED    = &PD -> pd_SegmentData -> ps_PED;
  3078.                         Prefs    = &PD -> pd_Preferences;
  3079.  
  3080.                             /* Calculate the printer page size. */
  3081.  
  3082.                         PageWidth    = PED -> ped_XDotsInch * (Prefs -> PrintRightMargin - Prefs -> PrintLeftMargin + 1);
  3083.                         PageHeight    = PED -> ped_YDotsInch * Prefs -> PaperLength;
  3084.  
  3085.                         switch(Prefs -> PrintPitch)
  3086.                         {
  3087.                             case PICA:
  3088.  
  3089.                                 PageWidth /= 10;
  3090.                                 break;
  3091.  
  3092.                             case ELITE:
  3093.  
  3094.                                 PageWidth /= 12;
  3095.                                 break;
  3096.  
  3097.                             case FINE:
  3098.  
  3099.                                 PageWidth /= 15;
  3100.                                 break;
  3101.                         }
  3102.  
  3103.                         switch(Prefs -> PrintSpacing)
  3104.                         {
  3105.                             case SIX_LPI:
  3106.  
  3107.                                 PageHeight /= 6;
  3108.                                 break;
  3109.  
  3110.                             case EIGHT_LPI:
  3111.  
  3112.                                 PageHeight /= 8;
  3113.                                 break;
  3114.                         }
  3115.  
  3116.                         if(PageWidth < PED->ped_MaxXDots || (PageWidth > PED->ped_MaxXDots && PED->ped_MaxXDots > 0))
  3117.                             PageWidth = PED->ped_MaxXDots;
  3118.  
  3119.                         if(PageHeight < PED->ped_MaxYDots || (PageHeight > PED->ped_MaxYDots && PED->ped_MaxYDots > 0))
  3120.                             PageHeight = PED->ped_MaxYDots;
  3121.  
  3122.                             /* Set up the default colour values. */
  3123.  
  3124.                         if(Prefs -> PrintShade == SHADE_BW)
  3125.                         {
  3126.                             Depth        = 1;
  3127.                             NumColours    = 2;
  3128.                             CubeSize    = 0;
  3129.                         }
  3130.                         else
  3131.                         {
  3132.                             Depth        = 12;
  3133.                             NumColours    = 4096;
  3134.                             CubeSize    = 16;
  3135.                         }
  3136.  
  3137.                             /* Set the page size */
  3138.  
  3139.                         xdev -> width            = PageWidth;
  3140.                         xdev -> height            = PageHeight;
  3141.  
  3142.                             /* Get the DPI values */
  3143.  
  3144.                         xdev -> x_pixels_per_inch    = (double)PED -> ped_XDotsInch;
  3145.                         xdev -> y_pixels_per_inch    = (double)PED -> ped_YDotsInch;
  3146.  
  3147.                             /* Try to allocate a suitable bitmap.
  3148.                              * If an allocation fails, rescale the
  3149.                              * colour cube and bitmap depth and
  3150.                              * retry. Minimum are eight colours.
  3151.                              */
  3152.  
  3153.                         do
  3154.                         {
  3155.                                 /* Try to allocate the raster... */
  3156.  
  3157.                             if(!(xdev -> bitmap = CreateBitMap(xdev -> width,xdev -> height,Depth,NULL,NULL,TRUE)))
  3158.                             {
  3159.                                     /* Any chance to rescale the cube? */
  3160.  
  3161.                                 if(Depth < 2)
  3162.                                     break;
  3163.                                 else
  3164.                                 {
  3165.                                         /* One plane less... */
  3166.  
  3167.                                     Depth--;
  3168.  
  3169.                                         /* Rescale the cube. */
  3170.  
  3171.                                     while(CubeSize >= 2)
  3172.                                     {
  3173.                                         if((NumColours = CubeSize * CubeSize * CubeSize) <= (1 << Depth))
  3174.                                             break;
  3175.                                         else
  3176.                                             CubeSize--;
  3177.                                     }
  3178.  
  3179.                                         /* Less than eight colours? */
  3180.  
  3181.                                     if(CubeSize < 2)
  3182.                                         break;
  3183.                                 }
  3184.                             }
  3185.                         }
  3186.                         while(!xdev -> bitmap);
  3187.  
  3188.                             /* Got the bitmap? */
  3189.  
  3190.                         if(xdev -> bitmap)
  3191.                         {
  3192.                                 /* Allocate a suitable colour map. */
  3193.  
  3194.                             if(xdev -> colormap = GetColorMap(NumColours))
  3195.                             {
  3196.                                     /* Black & white only? */
  3197.  
  3198.                                 if(NumColours == 2)
  3199.                                 {
  3200.                                     SetRGB4CM(xdev -> colormap,0,0x0,0x0,0x0);
  3201.                                     SetRGB4CM(xdev -> colormap,1,0xF,0xF,0xF);
  3202.                                 }
  3203.                                 else
  3204.                                 {
  3205.                                     LONG i = 0,r,g,b,max = CubeSize - 1;
  3206.  
  3207.                                         /* Fill in the colour cube. */
  3208.  
  3209.                                     for(r = 0 ; r < CubeSize ; r++)
  3210.                                     {
  3211.                                         for(g = 0 ; g < CubeSize ; g++)
  3212.                                         {
  3213.                                             for(b = 0 ; b < CubeSize ; b++)
  3214.                                                 SetRGB4CM(xdev -> colormap,i++,(15 * r) / max,(15 * g) / max,(15 * b) / max);
  3215.                                         }
  3216.                                     }
  3217.  
  3218.                                     set_colour_printer_device((gx_device_amiga *)dev,CubeSize);
  3219.                                 }
  3220.  
  3221.                                 xdev -> printer -> io_ColorMap    = xdev -> colormap;
  3222.                                 xdev -> rport -> BitMap        = xdev -> bitmap;
  3223.  
  3224.                                 return(0);
  3225.                             }
  3226.                             else
  3227.                                 perror("Ghostscript: failed to allocate colour map");
  3228.                         }
  3229.                         else
  3230.                         {
  3231.                             char buffer[256];
  3232.  
  3233.                             sprintf(buffer,"Ghostscript: failed to allocate raster (wanted %ld, largest %ld)",(xdev -> width + 15) / 8 * xdev -> height * Depth,AvailMem(MEMF_ANY | MEMF_LARGEST));
  3234.  
  3235.                             perror(buffer);
  3236.                         }
  3237.                     }
  3238.                     else
  3239.                     {
  3240.                         char buffer[256];
  3241. #ifdef IXEMUL
  3242.                         sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  3243. #endif
  3244.                         sprintf(buffer,"Ghostscript: failed to query printer page size (error code #%d)",xdev -> printer -> io_Error);
  3245.  
  3246.                         perror(buffer);
  3247.                     }
  3248.                 }
  3249.                 else
  3250.                     perror("Ghostscript: failed to allocate raster port");
  3251.             }
  3252.             else
  3253.             {
  3254.                 char buffer[256];
  3255.  
  3256.                 sprintf(buffer,"Ghostscript: failed to open printer.device (error code #%d)",xdev -> printer -> io_Error);
  3257.  
  3258.                 perror(buffer);
  3259.             }
  3260.         }
  3261.         else
  3262.             perror("Ghostscript: failed to allocate device driver");
  3263.     }
  3264.     else
  3265.         perror("Ghostscript: failed to create io port");
  3266.  
  3267.     return(-1);
  3268. }
  3269.  
  3270.     /* amiga_output_page_printer(gx_device *dev,int,int):
  3271.      *
  3272.      *    Send a bitmap to the printer.
  3273.      */
  3274.  
  3275. int
  3276. amiga_output_page_printer(gx_device *dev,int num_copies,int flush)
  3277. {
  3278.     const sigset_t trapped = sigmask(SIGINT);
  3279.     int result,i;
  3280.     ULONG Signals;
  3281.  
  3282.     xdev -> printer -> io_Command    = PRD_DUMPRPORT;
  3283.     xdev -> printer -> io_SrcWidth    = xdev -> width;
  3284.     xdev -> printer -> io_SrcHeight    = xdev -> height;
  3285.     xdev -> printer -> io_DestCols    = xdev -> width;
  3286.     xdev -> printer -> io_DestRows    = xdev -> height;
  3287.  
  3288.         /* We cannot possibly allow being interrupted in the middle
  3289.          * of a raster dump!
  3290.          */
  3291. #ifdef IXEMUL
  3292.     sigprocmask(SIG_BLOCK,&trapped,NULL);
  3293. #endif
  3294.     for(i = 0 ; i < num_copies ; i++)
  3295.     {
  3296.         SetSignal(0,SIGBREAKF_CTRL_C | (1L << xdev -> port -> mp_SigBit));
  3297.  
  3298.         SendIO((struct IORequest *)xdev -> printer);
  3299.  
  3300.         Signals = Wait(SIGBREAKF_CTRL_C | (1L << xdev -> port -> mp_SigBit));
  3301.  
  3302.         if(Signals & SIGBREAKF_CTRL_C)
  3303.         {
  3304.             char buffer[256];
  3305.  
  3306.             if(!CheckIO((struct IORequest *)xdev -> printer))
  3307.                 AbortIO((struct IORequest *)xdev -> printer);
  3308.  
  3309.             WaitIO((struct IORequest *)xdev -> printer);
  3310.  
  3311.             sprintf(buffer,"Ghostscript: printing aborted");
  3312.  
  3313.             perror(buffer);
  3314.  
  3315.             result = -1;
  3316. #ifdef IXEMUL
  3317.             sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  3318. #endif
  3319.             break;
  3320.         }
  3321.  
  3322.         if(Signals & (1L << xdev -> port -> mp_SigBit))
  3323.         {
  3324.             if(WaitIO((struct IORequest *)xdev -> printer))
  3325.             {
  3326.                 char buffer[256];
  3327.  
  3328.                 sprintf(buffer,"Ghostscript: failed to print raster (error code #%d)",xdev -> printer -> io_Error);
  3329.  
  3330.                 perror(buffer);
  3331.  
  3332.                 result = -1;
  3333. #ifdef IXEMUL
  3334.                 sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  3335. #endif
  3336.                 break;
  3337.             }
  3338.             else
  3339.                 result = 0;
  3340.         }
  3341.     }
  3342. #ifdef IXEMUL
  3343.     sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  3344. #endif
  3345.     return(result);
  3346. }
  3347.  
  3348.     /* amiga_close_printer(gx_device *dev):
  3349.      *
  3350.      *    Close the printer driver.
  3351.      */
  3352.  
  3353. int
  3354. amiga_close_printer(gx_device *dev)
  3355. {
  3356.     if(xdev -> bitmap)
  3357.     {
  3358.         DeleteBitMap(xdev -> bitmap,TRUE);
  3359.  
  3360.         xdev -> bitmap = NULL;
  3361.     }
  3362.  
  3363.     if(xdev -> rport)
  3364.     {
  3365.         FreeVec(xdev -> rport);
  3366.  
  3367.         xdev -> rport = NULL;
  3368.     }
  3369.  
  3370.     if(xdev -> colormap)
  3371.     {
  3372.         FreeColorMap(xdev -> colormap);
  3373.  
  3374.         xdev -> colormap = NULL;
  3375.     }
  3376.  
  3377.     if(xdev -> printer)
  3378.     {
  3379.         if(xdev -> printer -> io_Device)
  3380.             CloseDevice((struct IORequest *)xdev -> printer);
  3381.  
  3382.         DeleteIORequest(xdev -> printer);
  3383.  
  3384.         xdev -> printer = NULL;
  3385.     }
  3386.  
  3387.     if(xdev -> port)
  3388.     {
  3389.         DeleteMsgPort(xdev -> port);
  3390.  
  3391.         xdev -> port = NULL;
  3392.     }
  3393.  
  3394.     xdev -> width = xdev -> height = 0;
  3395.  
  3396.     return(0);
  3397. }
  3398.  
  3399.     /* amiga_open(gx_device *dev,ULONG Mode):
  3400.      *
  3401.      *    Open a custom screen.
  3402.      */
  3403.  
  3404. int
  3405. amiga_open(gx_device *dev,ULONG Mode)
  3406. {
  3407.     struct DisplayInfo    DisplayInfo;
  3408.     struct DimensionInfo    DimensionInfo;
  3409.  
  3410.         /* Get the display dimensions. */
  3411.  
  3412.     if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,Mode) && GetDisplayInfoData(NULL,(APTR)&DimensionInfo,sizeof(struct DimensionInfo),DTAG_DIMS,Mode))
  3413.     {
  3414.             /* Two shades only, black & white */
  3415.  
  3416.         STATIC struct ColorSpec Colours[] =
  3417.         {
  3418.              0,    0x0000, 0x0000, 0x0000,
  3419.              1,    0xFFFF, 0xFFFF, 0xFFFF,
  3420.  
  3421.             -1
  3422.         };
  3423.  
  3424.         double    Width,
  3425.             Height;
  3426.         LONG    i,cube_size,max;
  3427.         LONG    ScreenWidth,
  3428.             ScreenHeight,
  3429.             ScreenDepth;
  3430.  
  3431.             /* Start up with a maximum depth display. */
  3432.  
  3433.         ScreenDepth = DimensionInfo . MaxDepth;
  3434.  
  3435.             /* Check to see whether we will be able to
  3436.              * build a colour display or not.
  3437.              */
  3438.  
  3439.         for(cube_size = 6 ; cube_size >= 2 ; cube_size--)
  3440.         {
  3441.             if((max = cube_size * cube_size * cube_size) <= 1 << ScreenDepth)
  3442.                 break;
  3443.         }
  3444.  
  3445.             /* Got enough colours? */
  3446.  
  3447.         if(cube_size != 1)
  3448.             set_colour_device((gx_device_amiga *)dev,cube_size,NULL);
  3449.         else
  3450.         {
  3451.             ScreenDepth = 1;
  3452.  
  3453.             set_mono_device((gx_device_amiga *)dev);
  3454.         }
  3455.  
  3456.         if(xdev -> width > 0 && xdev -> height > 0)
  3457.         {
  3458.             Width    = xdev -> width;
  3459.             Height    = xdev -> height;
  3460.         }
  3461.         else
  3462.         {
  3463.             if(xdev -> page_width > 0.0)
  3464.                 Width = xdev -> page_width;
  3465.             else
  3466.                 Width = 0.0;
  3467.  
  3468.             if(xdev -> page_height > 0.0)
  3469.                 Height = xdev -> page_height;
  3470.             else
  3471.                 Height = 0.0;
  3472.         }
  3473.  
  3474.  
  3475.             /* Try to open a custom screen; if this fails, try to
  3476.              * rescale the colour cube and retry.
  3477.              */
  3478.  
  3479.         do
  3480.         {
  3481.             if(!(xdev -> screen = OpenScreenTags(NULL,
  3482.                 SA_Depth,    ScreenDepth,
  3483.                 SA_Overscan,    OSCAN_TEXT,
  3484.                 SA_Quiet,    TRUE,
  3485.                 SA_Behind,    TRUE,
  3486.                 SA_DisplayID,    Mode,
  3487.                 SA_Colors,    Colours,
  3488.                 SA_AutoScroll,    TRUE,
  3489.                 SA_ShowTitle,    FALSE,
  3490.                 SA_Title,    "Ghostscript Amiga output screen",
  3491.                 Width  > 0 ? SA_Width  : TAG_IGNORE,    Width,
  3492.                 Height > 0 ? SA_Height : TAG_IGNORE,    Height,
  3493.             TAG_DONE)))
  3494.             {
  3495.                 if(ScreenDepth < 2)
  3496.                     break;
  3497.                 else
  3498.                 {
  3499.                     ScreenDepth--;
  3500.  
  3501.                         /* Check to see whether we will be able to
  3502.                          * build a colour display or not.
  3503.                          */
  3504.  
  3505.                     while(cube_size >= 2)
  3506.                     {
  3507.                         if((max = cube_size * cube_size * cube_size) <= 1 << ScreenDepth)
  3508.                             break;
  3509.                         else
  3510.                             cube_size--;
  3511.                     }
  3512.  
  3513.                         /* Got enough colours? */
  3514.  
  3515.                     if(cube_size == 1 || ScreenDepth == 1)
  3516.                     {
  3517.                             /* Obviously not. */
  3518.  
  3519.                         ScreenDepth = 1;
  3520.  
  3521.                         set_mono_device((gx_device_amiga *)dev);
  3522.                     }
  3523.                 }
  3524.             }
  3525.         }
  3526.         while(!xdev -> screen);
  3527.  
  3528.             /* Did we succeed in opening the screen? */
  3529.  
  3530.         if(xdev -> screen)
  3531.         {
  3532.             if((xdev -> window = OpenWindowTags(NULL,
  3533.                 WA_Left,    0,
  3534.                 WA_Top,        0,
  3535.                 WA_Width,    xdev -> screen -> Width,
  3536.                 WA_Height,    xdev -> screen -> Height,
  3537.                 WA_Backdrop,    TRUE,
  3538.                 WA_RMBTrap,    TRUE,
  3539.                 WA_Borderless,    TRUE,
  3540.                 WA_CustomScreen,xdev -> screen,
  3541.             TAG_DONE)) != NULL)
  3542.             {
  3543.                 xdev -> rport    = xdev -> window -> RPort;
  3544.                 xdev -> width    = xdev -> screen -> Width;
  3545.                 xdev -> height    = xdev -> screen -> Height;
  3546.             }
  3547.             else
  3548.             {
  3549.                 xdev -> rport    = &xdev -> screen -> RastPort;
  3550.                 xdev -> width    = xdev -> screen -> Width;
  3551.                 xdev -> height    = xdev -> screen -> Height;
  3552.             }
  3553.  
  3554.                 /* Establish defaults. */
  3555.  
  3556.             DarkPen        = 0;
  3557.             LightPen    = 1;
  3558.  
  3559.             SetBPen(xdev -> rport,0);
  3560.             SetDrMd(xdev -> rport,JAM2);
  3561.  
  3562.                 /* Create the temporary drawing area. */
  3563.  
  3564.             if((xdev -> temp_rport = CreateTempRPort(xdev -> rport)) != NULL)
  3565.             {
  3566.                 if((xdev -> temp_array = (UBYTE *)AllocVec((xdev -> screen -> Width + 15) & ~15,MEMF_ANY)) != NULL)
  3567.                 {
  3568.                         /* Colour output enabled? */
  3569.  
  3570.                     if(xdev -> cube_size > 0)
  3571.                     {
  3572.                         LONG r,g,b,max = xdev -> cube_size - 1;
  3573.  
  3574.                         i = 0;
  3575.  
  3576.                             /* Build a suitable colour map. */
  3577.  
  3578.                         if(GfxBase -> LibNode . lib_Version >= 39)
  3579.                         {
  3580.                             for(r = 0 ; r < xdev -> cube_size ; r++)
  3581.                             {
  3582.                                 for(g = 0 ; g < xdev -> cube_size ; g++)
  3583.                                 {
  3584.                                     for(b = 0 ; b < xdev -> cube_size ; b++)
  3585.                                         SetRGB32(&xdev -> screen -> ViewPort,i++,SPREAD((255 * r) / max),SPREAD((255 * g) / max),SPREAD((255 * b) / max));
  3586.                                 }
  3587.                             }
  3588.                         }
  3589.                         else
  3590.                         {
  3591.                             for(r = 0 ; r < xdev -> cube_size ; r++)
  3592.                             {
  3593.                                 for(g = 0 ; g < xdev -> cube_size ; g++)
  3594.                                 {
  3595.                                     for(b = 0 ; b < xdev -> cube_size ; b++)
  3596.                                         SetRGB4(&xdev -> screen -> ViewPort,i++,(15 * r) / max,(15 * g) / max,(15 * b) / max);
  3597.                                 }
  3598.                             }
  3599.                         }
  3600.                     }
  3601.                 }
  3602.                 else
  3603.                 {
  3604.                     perror("Ghostscript: failed to allocate temporary line");
  3605.  
  3606.                     return(-1);
  3607.                 }
  3608.             }
  3609.             else
  3610.             {
  3611.                 perror("Ghostscript: failed to allocate temporary raster");
  3612.  
  3613.                 return(-1);
  3614.             }
  3615.  
  3616.             amiga_set_pen(dev,DarkPen);
  3617.  
  3618.             return(0);
  3619.         }
  3620.         else
  3621.             perror("Ghostscript: failed to open screen");
  3622.     }
  3623.     else
  3624.         perror("Ghostscript: failed to get display mode information");
  3625.  
  3626.     return(-1);
  3627. }
  3628.  
  3629.     /* amiga_output_page(gx_device *dev,int,int):
  3630.      *
  3631.      *    Page is not `buffered', just bring screen/window
  3632.      *    to the front.
  3633.      */
  3634.  
  3635. int
  3636. amiga_output_page(gx_device *dev,int num_copies,int flush)
  3637. {
  3638.     if(xdev -> screen)
  3639.         ScreenToFront(xdev -> screen);
  3640.     else
  3641.     {
  3642.         if(xdev -> window)
  3643.             WindowToFront(xdev -> window);
  3644.     }
  3645.  
  3646.     return(0);
  3647. }
  3648.  
  3649.     /* amiga_close(gx_device *dev):
  3650.      *
  3651.      *    Close the screen and free associated resources.
  3652.      */
  3653.  
  3654. int
  3655. amiga_close(gx_device *dev)
  3656. {
  3657.     if(xdev -> dispatcher)
  3658.     {
  3659.         const sigset_t trapped = sigmask(SIGINT);
  3660. #ifdef IXEMUL
  3661.         sigprocmask(SIG_BLOCK,&trapped,NULL);
  3662. #endif
  3663.         Forbid();
  3664.  
  3665.         Signal(xdev -> dispatcher,SIG_KILL);
  3666.  
  3667.         SetSignal(0,SIG_HANDSHAKE);
  3668.  
  3669.         Wait(SIG_HANDSHAKE);
  3670.  
  3671.         Permit();
  3672. #ifdef IXEMUL
  3673.         sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  3674. #endif
  3675.     }
  3676.  
  3677.     if(xdev -> temp_array)
  3678.     {
  3679.         FreeVec(xdev -> temp_array);
  3680.  
  3681.         xdev -> temp_array = NULL;
  3682.     }
  3683.  
  3684.     if(xdev -> pens)
  3685.     {
  3686.         LONG i;
  3687.  
  3688.         for(i = 0 ; i < xdev -> cube_size * xdev -> cube_size * xdev -> cube_size ; i++)
  3689.         {
  3690.             if(xdev -> pens[i] != -1)
  3691.                 ReleasePen(xdev -> window -> WScreen -> ViewPort . ColorMap,xdev -> pens[i]);
  3692.         }
  3693.  
  3694.         FreeVec(xdev -> pens);
  3695.  
  3696.         xdev -> pens = NULL;
  3697.     }
  3698.  
  3699.     if(xdev -> temp_rport)
  3700.     {
  3701.         DeleteTempRPort(xdev -> temp_rport);
  3702.  
  3703.         xdev -> temp_rport = NULL;
  3704.     }
  3705.  
  3706.     if(xdev -> window)
  3707.     {
  3708.         CloseWindow(xdev -> window);
  3709.  
  3710.         xdev -> window = NULL;
  3711.     }
  3712.  
  3713.     DeleteScrollers(dev);
  3714.  
  3715.     if(xdev -> super_bitmap)
  3716.     {
  3717.         DeleteBitMap(xdev -> super_bitmap,FALSE);
  3718.  
  3719.         xdev -> super_bitmap = NULL;
  3720.     }
  3721.  
  3722.     if(xdev -> screen)
  3723.     {
  3724.         CloseScreen(xdev -> screen);
  3725.  
  3726.         xdev -> screen = NULL;
  3727.     }
  3728.  
  3729.     xdev -> width = xdev -> height = 0;
  3730.  
  3731.     return(0);
  3732. }
  3733.  
  3734.     /* amiga_fill_rectangle(gx_device *dev,int x,int y,int w,int h,gx_color_index color):
  3735.      *
  3736.      *    Fill a rectangle with a given colour. This one is simple as it can
  3737.      *    be done with the Amiga graphics primitives.
  3738.      */
  3739.  
  3740. int
  3741. amiga_fill_rectangle(gx_device *dev,int x,int y,int w,int h,gx_color_index color)
  3742. {
  3743.     if(x < 0 || x > xdev -> width - w || y < 0 || y > xdev -> height - h)
  3744.         return(0);
  3745.     else
  3746.     {
  3747.         if(w > 0 && h > 0 && color != gx_no_color_index)
  3748.         {
  3749.             amiga_set_pen(dev,color);
  3750.  
  3751.             RectFill(xdev -> rport,x,y,x + w - 1,y + h - 1);
  3752.         }
  3753.  
  3754.         return(0);
  3755.     }
  3756. }
  3757.  
  3758.     /* amiga_copy_mono():
  3759.      *
  3760.      *    Copy a monochrome image. This operation requires a bit of work as
  3761.      *    we cannot simply blit the image into the bitmap.
  3762.      */
  3763.  
  3764. int
  3765. amiga_copy_mono(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)
  3766. {
  3767.     if(y < 0 || x < 0 || w < 0 || h < 0)
  3768.         return(0);
  3769.     else
  3770.     {
  3771.         if(w > 0 && h > 0)
  3772.         {
  3773.             LONG i,j;
  3774.  
  3775.             if(zero == gx_no_color_index)
  3776.             {
  3777.                 if(one != gx_no_color_index)
  3778.                 {
  3779.                     WORD word_width = (w + 15) & ~15;
  3780.  
  3781.                     do
  3782.                     {
  3783.                         ReadPixelLine8(xdev -> rport,x,y,word_width,xdev -> temp_array,xdev -> temp_rport);
  3784.  
  3785.                         for(i = sourcex, j = 0 ; i < sourcex + w ; i++, j++)
  3786.                         {
  3787.                             if(base[i >> 3] & shift[i & 7])
  3788.                                 xdev -> temp_array[j] = one;
  3789.                         }
  3790.  
  3791.                         WritePixelLine8(xdev -> rport,x,y,word_width,xdev -> temp_array,xdev -> temp_rport);
  3792.  
  3793.                         base += raster;
  3794.  
  3795.                         y++;
  3796.                     }
  3797.                     while(--h);
  3798.                 }
  3799.             }
  3800.             else
  3801.             {
  3802.                 if(one == gx_no_color_index)
  3803.                 {
  3804.                     WORD word_width = (w + 15) & ~15;
  3805.  
  3806.                     do
  3807.                     {
  3808.                         ReadPixelLine8(xdev -> rport,x,y,word_width,xdev -> temp_array,xdev -> temp_rport);
  3809.  
  3810.                         for(i = sourcex, j = 0 ; i < w + sourcex ; i++, j++)
  3811.                         {
  3812.                             if(!(base[i >> 3] & shift[i & 7]))
  3813.                                 xdev -> temp_array[j] = zero;
  3814.                         }
  3815.  
  3816.                         WritePixelLine8(xdev -> rport,x,y,word_width,xdev -> temp_array,xdev -> temp_rport);
  3817.  
  3818.                         base += raster;
  3819.  
  3820.                         y++;
  3821.                     }
  3822.                     while(--h);
  3823.                 }
  3824.                 else
  3825.                 {
  3826.                     do
  3827.                     {
  3828.                         for(i = sourcex, j = 0 ; i < w + sourcex ; i++, j++)
  3829.                         {
  3830.                             if(base[i >> 3] & shift[i & 7])
  3831.                                 xdev -> temp_array[j] = one;
  3832.                             else
  3833.                                 xdev -> temp_array[j] = zero;
  3834.                         }
  3835.  
  3836.                         WritePixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3837.  
  3838.                         base += raster;
  3839.  
  3840.                         y++;
  3841.                     }
  3842.                     while(--h);
  3843.                 }
  3844.             }
  3845.         }
  3846.  
  3847.         return(0);
  3848.     }
  3849. }
  3850.  
  3851.     /* amiga_copy_color():
  3852.      *
  3853.      *    Copy a color image (oh well...). This is just the same as the
  3854.      *    copy_mono() routine.
  3855.      */
  3856.  
  3857. int
  3858. amiga_copy_color(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)
  3859. {
  3860.     if(y < 0 || x < 0 || w < 0 || h < 0)
  3861.         return(0);
  3862.     else
  3863.     {
  3864.         if(w > 0 && h > 0)
  3865.         {
  3866.             LONG i,j;
  3867.  
  3868.             do
  3869.             {
  3870.                 for(i = sourcex, j = 0 ; i < w + sourcex ; i++, j++)
  3871.                 {
  3872.                     if(base[i >> 3] & shift[i & 7])
  3873.                         xdev -> temp_array[j] = DarkPen;
  3874.                     else
  3875.                         xdev -> temp_array[j] = LightPen;
  3876.                 }
  3877.  
  3878.                 WritePixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3879.  
  3880.                 base += raster;
  3881.  
  3882.                 y++;
  3883.             }
  3884.             while(--h);
  3885.         }
  3886.  
  3887.         return(0);
  3888.     }
  3889. }
  3890.  
  3891.     /* amiga_draw_line(gx_device *dev,int x0,int y0,int x1,int y1,gx_color_index color):
  3892.      *
  3893.      *    Draw a line between two points. This one is easy as it can be done
  3894.      *    with the Amiga graphics primitives, the only glitch is having to reset
  3895.      *    the last dot to its original colour.
  3896.      */
  3897.  
  3898. int
  3899. amiga_draw_line(gx_device *dev,int x0,int y0,int x1,int y1,gx_color_index color)
  3900. {
  3901.     if(color != gx_no_color_index && (x0 != x1 || y0 != y1))
  3902.     {
  3903.         LONG pen;
  3904.  
  3905.         pen = ReadPixel(xdev -> rport,x1,y1);
  3906.  
  3907.         amiga_set_pen(dev,color);
  3908.  
  3909.         Move(xdev -> rport,x0,y0);
  3910.         Draw(xdev -> rport,x1,y1);
  3911.  
  3912.         if(pen == color)
  3913.         {
  3914.             amiga_set_pen(dev,pen);
  3915.  
  3916.             WritePixel(xdev -> rport,x1,y1);
  3917.         }
  3918.     }
  3919.  
  3920.     return(0);
  3921. }
  3922.  
  3923.     /* amiga_copy_mono_raw():
  3924.      *
  3925.      *    Copy a monochrome image to a bitmap. Just watch the
  3926.      *    astounding number of case switches.
  3927.      */
  3928.  
  3929. int
  3930. amiga_copy_mono_raw(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)
  3931. {
  3932.     if(y < 0 || x < 0 || w < 0 || h < 0)
  3933.         return(0);
  3934.     else
  3935.     {
  3936.         if(w > 0 && h > 0)
  3937.         {
  3938.             LONG i,j,modulo = xdev -> rport -> BitMap -> BytesPerRow;
  3939.             UBYTE *line;
  3940.  
  3941.             w += sourcex;
  3942.  
  3943.             line = xdev -> rport -> BitMap -> Planes[0] + y * xdev -> rport -> BitMap -> BytesPerRow;
  3944.  
  3945.             if(zero == gx_no_color_index)
  3946.             {
  3947.                 if(one != gx_no_color_index)
  3948.                 {
  3949.                     if(one)
  3950.                     {
  3951.                         do
  3952.                         {
  3953.                             for(i = sourcex, j = x ; i < w ; i++, j++)
  3954.                             {
  3955.                                 if(base[i >> 3] & shift[i & 7])
  3956.                                     line[j >> 3] |= shift[j & 7];
  3957.                             }
  3958.  
  3959.                             base += raster;
  3960.  
  3961.                             line += modulo;
  3962.                         }
  3963.                         while(--h);
  3964.                     }
  3965.                     else
  3966.                     {
  3967.                         do
  3968.                         {
  3969.                             for(i = sourcex, j = x ; i < w ; i++, j++)
  3970.                             {
  3971.                                 if(base[i >> 3] & shift[i & 7])
  3972.                                     line[j >> 3] &= masks[j & 7];
  3973.                             }
  3974.  
  3975.                             base += raster;
  3976.  
  3977.                             line += modulo;
  3978.                         }
  3979.                         while(--h);
  3980.                     }
  3981.                 }
  3982.             }
  3983.             else
  3984.             {
  3985.                 if(one == gx_no_color_index)
  3986.                 {
  3987.                     if(zero)
  3988.                     {
  3989.                         do
  3990.                         {
  3991.                             for(i = sourcex, j = x ; i < w ; i++, j++)
  3992.                             {
  3993.                                 if(!(base[i >> 3] & shift[i & 7]))
  3994.                                     line[j >> 3] |= shift[j & 7];
  3995.                             }
  3996.  
  3997.                             base += raster;
  3998.  
  3999.                             line += modulo;
  4000.                         }
  4001.                         while(--h);
  4002.                     }
  4003.                     else
  4004.                     {
  4005.                         do
  4006.                         {
  4007.                             for(i = sourcex, j = x ; i < w ; i++, j++)
  4008.                             {
  4009.                                 if(!(base[i >> 3] & shift[i & 7]))
  4010.                                     line[j >> 3] &= masks[j & 7];
  4011.                             }
  4012.  
  4013.                             base += raster;
  4014.  
  4015.                             line += modulo;
  4016.                         }
  4017.                         while(--h);
  4018.                     }
  4019.                 }
  4020.                 else
  4021.                 {
  4022.                     if(one)
  4023.                     {
  4024.                         do
  4025.                         {
  4026.                             for(i = sourcex, j = x ; i < w ; i++, j++)
  4027.                             {
  4028.                                 if(base[i >> 3] & shift[i & 7])
  4029.                                     line[j >> 3] |= shift[j & 7];
  4030.                                 else
  4031.                                     line[j >> 3] &= masks[j & 7];
  4032.                             }
  4033.  
  4034.                             base += raster;
  4035.  
  4036.                             line += modulo;
  4037.                         }
  4038.                         while(--h);
  4039.                     }
  4040.                     else
  4041.                     {
  4042.                         do
  4043.                         {
  4044.                             for(i = sourcex, j = x ; i < w ; i++, j++)
  4045.                             {
  4046.                                 if(base[i >> 3] & shift[i & 7])
  4047.                                     line[j >> 3] &= masks[j & 7];
  4048.                                 else
  4049.                                     line[j >> 3] |= shift[j & 7];
  4050.                             }
  4051.  
  4052.                             base += raster;
  4053.  
  4054.                             line += modulo;
  4055.                         }
  4056.                         while(--h);
  4057.                     }
  4058.                 }
  4059.             }
  4060.         }
  4061.  
  4062.         return(0);
  4063.     }
  4064. }
  4065.  
  4066.     /* amiga_copy_color_raw():
  4067.      *
  4068.      *    Copy a color image (oh well...). This is just the same as the
  4069.      *    copy_mono() routine.
  4070.      */
  4071.  
  4072. int
  4073. amiga_copy_color_raw(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)
  4074. {
  4075.     if(y < 0 || x < 0 || w < 0 || h < 0)
  4076.         return(0);
  4077.     else
  4078.     {
  4079.         if(w > 0 && h > 0)
  4080.         {
  4081.             LONG i,j,modulo = xdev -> rport -> BitMap -> BytesPerRow;
  4082.             UBYTE *line;
  4083.  
  4084.             line = xdev -> rport -> BitMap -> Planes[0] + y * xdev -> rport -> BitMap -> BytesPerRow;
  4085.  
  4086.             w += sourcex;
  4087.  
  4088.             do
  4089.             {
  4090.                 for(i = sourcex, j = x ; i < w ; i++, j++)
  4091.                 {
  4092.                     if(base[i >> 3] & shift[i & 7])
  4093.                         line[j >> 3] |= shift[j & 7];
  4094.                     else
  4095.                         line[j >> 3] &= masks[j & 7];
  4096.                 }
  4097.  
  4098.                 base += raster;
  4099.  
  4100.                 line += modulo;
  4101.             }
  4102.             while(--h);
  4103.         }
  4104.  
  4105.         return(0);
  4106.     }
  4107. }
  4108.  
  4109.     /* amiga_fill_rectangle_raw():
  4110.      *
  4111.      *    Fill a rectangular area in a bitmap.
  4112.      */
  4113.  
  4114. int
  4115. amiga_fill_rectangle_raw(gx_device *dev,int x,int y,int w,int h,gx_color_index color)
  4116. {
  4117.     if(x < 0 || x > xdev -> width - w || y < 0 || y > xdev -> height - h)
  4118.         return(0);
  4119.     else
  4120.     {
  4121.         if(w > 0 && h > 0 && color != gx_no_color_index)
  4122.         {
  4123.             UBYTE *line,startmask,endmask;
  4124.             LONG right,mid,modulo = xdev -> rport -> BitMap -> BytesPerRow;
  4125.  
  4126.             right    = x + w;
  4127.             mid    = (right >> 3) - (x >> 3);
  4128.             line    = xdev -> rport -> BitMap -> Planes[0] + y * xdev -> rport -> BitMap -> BytesPerRow + (x >> 3);
  4129.  
  4130.             x    &= 7;
  4131.             right    &= 7;
  4132.  
  4133.             if(color)
  4134.             {
  4135.                 startmask    = 0xFF >> x;
  4136.                 endmask        = ~(0xFF >> right);
  4137.  
  4138.                 if(mid)
  4139.                 {
  4140.                     UBYTE *ptr;
  4141.                     int i;
  4142.  
  4143.                     do
  4144.                     {
  4145.                         ptr = line;
  4146.  
  4147.                         *ptr++ |= startmask;
  4148.  
  4149.                         i = mid;
  4150.  
  4151.                         while(--i > 0)
  4152.                             *ptr++ = 0xFF;
  4153.  
  4154.                         *ptr |= endmask;
  4155.  
  4156.                         line += modulo;
  4157.                     }
  4158.                     while(--h);
  4159.                 }
  4160.                 else
  4161.                 {
  4162.                     startmask &= endmask;
  4163.  
  4164.                     do
  4165.                     {
  4166.                         *line |= startmask;
  4167.  
  4168.                         line += modulo;
  4169.                     }
  4170.                     while(--h);
  4171.                 }
  4172.             }
  4173.             else
  4174.             {
  4175.                 startmask    = ~(0xFF >> x);
  4176.                 endmask        = 0xFF >> right;
  4177.  
  4178.                 if(mid)
  4179.                 {
  4180.                     UBYTE *ptr;
  4181.                     LONG i;
  4182.  
  4183.                     do
  4184.                     {
  4185.                         ptr = line;
  4186.  
  4187.                         *ptr++ &= startmask;
  4188.  
  4189.                         i = mid;
  4190.  
  4191.                         while(--i > 0)
  4192.                             *ptr++ = 0x00;
  4193.  
  4194.                         *ptr &= endmask;
  4195.  
  4196.                         line += modulo;
  4197.                     }
  4198.                     while(--h);
  4199.                 }
  4200.                 else
  4201.                 {
  4202.                     startmask |= endmask;
  4203.  
  4204.                     do
  4205.                     {
  4206.                         *line &= startmask;
  4207.  
  4208.                         line += modulo;
  4209.                     }
  4210.                     while(--h);
  4211.                 }
  4212.             }
  4213.         }
  4214.  
  4215.         return(0);
  4216.     }
  4217. }
  4218.  
  4219.     /* amiga_draw_line_raw():
  4220.      *
  4221.      *    Draw a hair line, your basic DDA algorithm;
  4222.      *    keep your fingers crossed.
  4223.      */
  4224.  
  4225. int
  4226. amiga_draw_line_raw(gx_device *dev,int x,int y,int x1,int y1,gx_color_index color)
  4227. {
  4228.     if(color != gx_no_color_index && (x != x1 || y != y1))
  4229.     {
  4230.         short xstep,ystep,dx,dy,diff,modulo;
  4231.         UBYTE *line,*plane,pen;
  4232.         LONG last;
  4233.  
  4234.         modulo    = xdev -> rport -> BitMap -> BytesPerRow;
  4235.         plane    = xdev -> rport -> BitMap -> Planes[0];
  4236.  
  4237.         line    = &plane[y1 * modulo];
  4238.         last    = y1;
  4239.         pen    = line[x1 >> 3] & (x1 & 7);
  4240.  
  4241.         dx = x1 - x;
  4242.         dy = y1 - y;
  4243.  
  4244.         if(dx < 0)
  4245.         {
  4246.             dx = -dx;
  4247.             dy = -dy;
  4248.  
  4249.             x = x1;
  4250.             y = y1;
  4251.         }
  4252.  
  4253.         if(y != last)
  4254.             line = &plane[(last = y) * modulo];
  4255.  
  4256.         if(color)
  4257.         {
  4258.             line[x >> 3] |= shift[x & 7];
  4259.  
  4260.             xstep = ystep = 0;
  4261.  
  4262.             if(dy < 0)
  4263.             {
  4264.                 if(dx > -dy)
  4265.                 {
  4266.                     diff = -dx / 2;
  4267.  
  4268.                     do
  4269.                     {
  4270.                         xstep++;
  4271.  
  4272.                         if(diff > 0)
  4273.                         {
  4274.                             ystep--;
  4275.  
  4276.                             diff = diff - dy - dx;
  4277.                         }
  4278.                         else
  4279.                             diff -= dy;
  4280.  
  4281.                         {
  4282.                             LONG x1 = x + xstep,y1 = y + ystep;
  4283.  
  4284.                             if(y1 != last)
  4285.                                 line = &plane[(last = y1) * modulo];
  4286.  
  4287.                             line[x1 >> 3] |= shift[x1 & 7];
  4288.                         }
  4289.                     }
  4290.                     while(xstep < dx);
  4291.                 }
  4292.                 else
  4293.                 {
  4294.                     if(dx == -dy)
  4295.                         diff = 0;
  4296.                     else
  4297.                         diff = -dy / 2;
  4298.  
  4299.                     do
  4300.                     {
  4301.                         ystep--;
  4302.  
  4303.                         if(diff > 0)
  4304.                             diff -= dx;
  4305.                         else
  4306.                         {
  4307.                             xstep++;
  4308.  
  4309.                             diff = diff - dy - dx;
  4310.                         }
  4311.  
  4312.                         {
  4313.                             LONG x1 = x + xstep,y1 = y + ystep;
  4314.  
  4315.                             if(y1 != last)
  4316.                                 line = &plane[(last = y1) * modulo];
  4317.  
  4318.                             line[x1 >> 3] |= shift[x1 & 7];
  4319.                         }
  4320.                     }
  4321.                     while(ystep > dy);
  4322.                 }
  4323.             }
  4324.             else
  4325.             {
  4326.                 if(dx > dy)
  4327.                 {
  4328.                     diff = -dx / 2;
  4329.  
  4330.                     do
  4331.                     {
  4332.                         xstep++;
  4333.  
  4334.                         if(diff > 0)
  4335.                         {
  4336.                             ystep++;
  4337.  
  4338.                             diff = diff + dy - dx;
  4339.                         }
  4340.                         else
  4341.                             diff += dy;
  4342.  
  4343.                         {
  4344.                             LONG x1 = x + xstep,y1 = y + ystep;
  4345.  
  4346.                             if(y1 != last)
  4347.                                 line = &plane[(last = y1) * modulo];
  4348.  
  4349.                             line[x1 >> 3] |= shift[x1 & 7];
  4350.                         }
  4351.                     }
  4352.                     while(xstep < dx);
  4353.                 }
  4354.                 else
  4355.                 {
  4356.                     if(dx == dy)
  4357.                         diff = 0;
  4358.                     else
  4359.                         diff = dy / 2;
  4360.  
  4361.                     do
  4362.                     {
  4363.                         ystep++;
  4364.  
  4365.                         if(diff > 0)
  4366.                             diff -= dx;
  4367.                         else
  4368.                         {
  4369.                             xstep++;
  4370.  
  4371.                             diff = diff + dy - dx;
  4372.                         }
  4373.  
  4374.                         {
  4375.                             LONG x1 = x + xstep,y1 = y + ystep;
  4376.  
  4377.                             if(y1 != last)
  4378.                                 line = &plane[(last = y1) * modulo];
  4379.  
  4380.                             line[x1 >> 3] |= shift[x1 & 7];
  4381.                         }
  4382.                     }
  4383.                     while(ystep < dy);
  4384.                 }
  4385.             }
  4386.  
  4387.             if(!pen)
  4388.             {
  4389.                 if(y1 != last)
  4390.                     line = &plane[(last = y1) * modulo];
  4391.  
  4392.                 line[x1 >> 3] &= masks[x1 & 7];
  4393.             }
  4394.         }
  4395.         else
  4396.         {
  4397.             line[x >> 3] &= masks[x & 7];
  4398.  
  4399.             xstep = ystep = 0;
  4400.  
  4401.             if(dy < 0)
  4402.             {
  4403.                 if(dx > -dy)
  4404.                 {
  4405.                     diff = -dx / 2;
  4406.  
  4407.                     do
  4408.                     {
  4409.                         xstep++;
  4410.  
  4411.                         if(diff > 0)
  4412.                         {
  4413.                             ystep--;
  4414.  
  4415.                             diff = diff - dy - dx;
  4416.                         }
  4417.                         else
  4418.                             diff -= dy;
  4419.  
  4420.                         {
  4421.                             LONG x1 = x + xstep,y1 = y + ystep;
  4422.  
  4423.                             if(y1 != last)
  4424.                                 line = &plane[(last = y1) * modulo];
  4425.  
  4426.                             line[x1 >> 3] &= masks[x1 & 7];
  4427.                         }
  4428.                     }
  4429.                     while(xstep < dx);
  4430.                 }
  4431.                 else
  4432.                 {
  4433.                     if(dx == -dy)
  4434.                         diff = 0;
  4435.                     else
  4436.                         diff = -dy / 2;
  4437.  
  4438.                     do
  4439.                     {
  4440.                         ystep--;
  4441.  
  4442.                         if(diff > 0)
  4443.                             diff -= dx;
  4444.                         else
  4445.                         {
  4446.                             xstep++;
  4447.  
  4448.                             diff = diff - dy - dx;
  4449.                         }
  4450.  
  4451.                         {
  4452.                             LONG x1 = x + xstep,y1 = y + ystep;
  4453.  
  4454.                             if(y1 != last)
  4455.                                 line = &plane[(last = y1) * modulo];
  4456.  
  4457.                             line[x1 >> 3] &= masks[x1 & 7];
  4458.                         }
  4459.                     }
  4460.                     while(ystep > dy);
  4461.                 }
  4462.             }
  4463.             else
  4464.             {
  4465.                 if(dx > dy)
  4466.                 {
  4467.                     diff = -dx / 2;
  4468.  
  4469.                     do
  4470.                     {
  4471.                         xstep++;
  4472.  
  4473.                         if(diff > 0)
  4474.                         {
  4475.                             ystep++;
  4476.  
  4477.                             diff = diff + dy - dx;
  4478.                         }
  4479.                         else
  4480.                             diff += dy;
  4481.  
  4482.                         {
  4483.                             LONG x1 = x + xstep,y1 = y + ystep;
  4484.  
  4485.                             if(y1 != last)
  4486.                                 line = &plane[(last = y1) * modulo];
  4487.  
  4488.                             line[x1 >> 3] &= masks[x1 & 7];
  4489.                         }
  4490.                     }
  4491.                     while(xstep < dx);
  4492.                 }
  4493.                 else
  4494.                 {
  4495.                     if(dx == dy)
  4496.                         diff = 0;
  4497.                     else
  4498.                         diff =  dy / 2;
  4499.  
  4500.                     do
  4501.                     {
  4502.                         ystep++;
  4503.  
  4504.                         if(diff > 0)
  4505.                             diff -= dx;
  4506.                         else
  4507.                         {
  4508.                             xstep++;
  4509.  
  4510.                             diff = diff + dy - dx;
  4511.                         }
  4512.  
  4513.                         {
  4514.                             LONG x1 = x + xstep,y1 = y + ystep;
  4515.  
  4516.                             if(y1 != last)
  4517.                                 line = &plane[(last = y1) * modulo];
  4518.  
  4519.                             line[x1 >> 3] &= masks[x1 & 7];
  4520.                         }
  4521.                     }
  4522.                     while(ystep < dy);
  4523.                 }
  4524.             }
  4525.  
  4526.             if(pen)
  4527.             {
  4528.                 if(y1 != last)
  4529.                     line = &plane[(last = y1) * modulo];
  4530.  
  4531.                 line[x1 >> 3] |= pen;
  4532.             }
  4533.         }
  4534.     }
  4535.  
  4536.     return(0);
  4537. }
  4538.  
  4539.     /* amiga_open_ilbm(gx_device *dev):
  4540.      *
  4541.      *    Open the ilbm device.
  4542.      */
  4543.  
  4544. int
  4545. amiga_open_ilbm(gx_device *dev)
  4546. {
  4547.     if(xdev -> width <= 0 || xdev -> height <= 0)
  4548.     {
  4549.         if(xdev -> page_width > 0.0)
  4550.             xdev -> width = (int)(xdev -> x_pixels_per_inch * xdev -> page_width);
  4551.         else
  4552.             xdev -> width = 640;
  4553.  
  4554.         if(xdev -> page_height > 0.0)
  4555.             xdev -> height = (int)(xdev -> y_pixels_per_inch * xdev -> page_height);
  4556.         else
  4557.             xdev -> height = 512;
  4558.     }
  4559.  
  4560.     if(xdev -> rport = (struct RastPort *)AllocVec(sizeof(struct RastPort),MEMF_ANY))
  4561.     {
  4562.         InitRastPort(xdev -> rport);
  4563.  
  4564.         if(xdev -> bitmap = (struct BitMap *)AllocVec(sizeof(struct BitMap),MEMF_ANY))
  4565.         {
  4566.             InitBitMap(xdev -> bitmap,1,xdev -> width,xdev -> height);
  4567.  
  4568.             if(xdev -> bitplane = AllocVec(xdev -> bitmap -> Rows * xdev -> bitmap -> BytesPerRow,MEMF_ANY | MEMF_CLEAR))
  4569.             {
  4570.                 xdev -> bitmap -> Planes[0]    = xdev -> bitplane;
  4571.                 xdev -> rport -> BitMap        = xdev -> bitmap;
  4572.                 xdev -> page_count        = 1;
  4573.  
  4574.                 DarkPen        = 0;
  4575.                 LightPen    = 1;
  4576.  
  4577.                 return(0);
  4578.             }
  4579.             else
  4580.             {
  4581.                 char buffer[256];
  4582.  
  4583.                 sprintf(buffer,"Ghostscript: failed to allocate raster (wanted %d, largest %ld)",xdev -> bitmap -> Rows * xdev -> bitmap -> BytesPerRow,AvailMem(MEMF_ANY | MEMF_LARGEST));
  4584.  
  4585.                 perror(buffer);
  4586.             }
  4587.         }
  4588.         else
  4589.             perror("Ghostscript: failed to allocate bitmap");
  4590.     }
  4591.     else
  4592.         perror("Ghostscript: failed to allocate raster port");
  4593.  
  4594.     return(-1);
  4595. }
  4596.  
  4597.     /* amiga_output_page_ilbm(gx_device *dev,int,int):
  4598.      *
  4599.      *    Send a bitmap to an IFF-ILBM file.
  4600.      */
  4601.  
  4602. int
  4603. amiga_output_page_ilbm(gx_device *dev,int num_copies,int flush)
  4604. {
  4605.     const sigset_t trapped = sigmask(SIGINT);
  4606.     char buffer[270];
  4607.     LONG result = -1;
  4608.  
  4609.     sprintf(buffer,"%s_%04d.ilbm",xdev -> file_name,xdev -> page_count);
  4610.  
  4611.     fprintf(stdout,"\n\033[ASaving page Nº%d to \"%s\"...\033[K",xdev -> page_count,buffer);
  4612.     fflush(stdout);
  4613. #ifdef IXEMUL
  4614.     sigprocmask(SIG_BLOCK,&trapped,NULL);
  4615. #endif
  4616.     if(SaveBitMap(buffer,xdev -> bitmap,xdev -> width,xdev -> height,(UWORD)xdev -> x_pixels_per_inch,xdev -> y_pixels_per_inch))
  4617.     {
  4618.         fprintf(stdout,"\n\033[APage saved to file \"%s\".\033[K\n",buffer);
  4619.  
  4620.         result = 0;
  4621.  
  4622.         xdev -> page_count++;
  4623.     }
  4624.     else
  4625.         perror("\n\033[AGhostscript: error saving page\033[K");
  4626. #ifdef IXEMUL
  4627.     sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  4628. #endif
  4629.     return(result);
  4630. }
  4631.  
  4632.     /* amiga_close_ilbm(gx_device *dev):
  4633.      *
  4634.      *    Close the ilbm driver.
  4635.      */
  4636.  
  4637. int
  4638. amiga_close_ilbm(gx_device *dev)
  4639. {
  4640.     if(xdev -> bitplane)
  4641.     {
  4642.         FreeVec(xdev -> bitplane);
  4643.  
  4644.         xdev -> bitplane = NULL;
  4645.     }
  4646.  
  4647.     if(xdev -> bitmap)
  4648.     {
  4649.         FreeVec(xdev -> bitmap);
  4650.  
  4651.         xdev -> bitmap = NULL;
  4652.     }
  4653.  
  4654.     if(xdev -> rport)
  4655.     {
  4656.         FreeVec(xdev -> rport);
  4657.  
  4658.         xdev -> rport = NULL;
  4659.     }
  4660.  
  4661.     xdev -> width = xdev -> height = 0;
  4662.  
  4663.     return(0);
  4664. }
  4665.  
  4666.     /* amiga_color_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue):
  4667.      *
  4668.      *    Turn an RGB colour into a pen index.
  4669.      */
  4670.  
  4671. gx_color_index
  4672. amiga_color_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue)
  4673. {
  4674.     LONG max = xdev -> cube_size - 1,r,g,b;
  4675.  
  4676.     r = (max * red)   / gx_max_color_value;
  4677.     g = (max * green) / gx_max_color_value;
  4678.     b = (max * blue)  / gx_max_color_value;
  4679.  
  4680.     return((r * xdev -> cube_size + g) * xdev -> cube_size + b);
  4681. }
  4682.  
  4683.     /* amiga_color_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3]):
  4684.      *
  4685.      *    Turn a pen index into RGB colour values.
  4686.      */
  4687.  
  4688. int
  4689. amiga_color_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3])
  4690. {
  4691.     LONG i,value,max = xdev -> cube_size - 1;
  4692.  
  4693.     for(i = 2 ; i >= 0 ; i--)
  4694.     {
  4695.         value = color % xdev -> cube_size;
  4696.  
  4697.         rgb[i] = (gx_max_color_value * value) / max;
  4698.  
  4699.         color /= xdev -> cube_size;
  4700.     }
  4701.  
  4702.     return(0);
  4703. }
  4704.  
  4705.     /* amiga_color_map_rgb_color_pen(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue):
  4706.      *
  4707.      *    Turn an RGB colour into a pen index; this routine takes remapped
  4708.      *    pens into account.
  4709.      */
  4710.  
  4711. gx_color_index
  4712. amiga_color_map_rgb_color_pen(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue)
  4713. {
  4714.     LONG max = xdev -> cube_size - 1,r,g,b;
  4715.  
  4716.     r = (max * red)   / gx_max_color_value;
  4717.     g = (max * green) / gx_max_color_value;
  4718.     b = (max * blue)  / gx_max_color_value;
  4719.  
  4720.     return(xdev -> pens[(r * xdev -> cube_size + g) * xdev -> cube_size + b]);
  4721. }
  4722.  
  4723.     /* amiga_color_map_color_rgb_pen(gx_device *dev,gx_color_index color,gx_color_value rgb[3]):
  4724.      *
  4725.      *    Turn a pen index into RGB colour values; this routine takes remapped
  4726.      *    pens into account.
  4727.      */
  4728.  
  4729. int
  4730. amiga_color_map_color_rgb_pen(gx_device *dev,gx_color_index color,gx_color_value rgb[3])
  4731. {
  4732.     LONG i,value,max = xdev -> cube_size - 1;
  4733.  
  4734.         /* Find the matching pen... */
  4735.  
  4736.     for(i = 0 ; i < xdev -> cube_size * xdev -> cube_size * xdev -> cube_size ; i++)
  4737.     {
  4738.         if(xdev -> pens[i] == color)
  4739.         {
  4740.             color = i;
  4741.  
  4742.             break;
  4743.         }
  4744.     }
  4745.  
  4746.     for(i = 2 ; i >= 0 ; i--)
  4747.     {
  4748.         value = color % xdev -> cube_size;
  4749.  
  4750.         rgb[i] = (gx_max_color_value * value) / max;
  4751.  
  4752.         color /= xdev -> cube_size;
  4753.     }
  4754.  
  4755.     return(0);
  4756. }
  4757.  
  4758.     /* amiga_copy_color8():
  4759.      *
  4760.      *    Copy a color image, the source is guaranteed to consist of
  4761.      *    one byte per colour.
  4762.      */
  4763.  
  4764. int
  4765. amiga_copy_color8(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)
  4766. {
  4767.     if(y < 0 || x < 0 || w < 0 || h < 0)
  4768.         return(0);
  4769.     else
  4770.     {
  4771.         if(w > 0 && h > 0)
  4772.         {
  4773.             base += sourcex;
  4774.  
  4775.             if(w > xdev -> width)
  4776.                 w = xdev -> width;
  4777.  
  4778.             do
  4779.             {
  4780.                 CopyMem((UBYTE *)base,xdev -> temp_array,w);
  4781.  
  4782.                 WritePixelLine8(xdev -> rport,x,y++,w,xdev -> temp_array,xdev -> temp_rport);
  4783.  
  4784.                 base += raster;
  4785.             }
  4786.             while(--h);
  4787.         }
  4788.  
  4789.         return(0);
  4790.     }
  4791. }
  4792.  
  4793.     /* amiga_copy_mono_raw_color():
  4794.      *
  4795.      *    Copy a monochrome image to a bitmap.
  4796.      */
  4797.  
  4798. int
  4799. amiga_copy_mono_raw_color(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)
  4800. {
  4801.     if(y < 0 || x < 0 || w < 0 || h < 0)
  4802.         return(0);
  4803.     else
  4804.     {
  4805.         if(w > 0 && h > 0 && zero != gx_no_color_index && one != gx_no_color_index)
  4806.         {
  4807.             PLANEPTR line[12];
  4808.             LONG i,j,k,modulo = xdev -> rport -> BitMap -> BytesPerRow,depth = xdev -> rport -> BitMap -> Depth;
  4809.  
  4810.             for(i = 0 ; i < depth ; i++)
  4811.                 line[i] = xdev -> rport -> BitMap -> Planes[i] + y * modulo;
  4812.  
  4813.             w += sourcex;
  4814.  
  4815.             if(zero == gx_no_color_index)
  4816.             {
  4817.                 do
  4818.                 {
  4819.                     for(i = sourcex, j = x ; i < w ; i++, j++)
  4820.                     {
  4821.                         if(base[i >> 3] & shift[i & 7])
  4822.                         {
  4823.                             for(k = 0 ; k < depth ; k++)
  4824.                             {
  4825.                                 if(one & (1 << k))
  4826.                                     line[k][j >> 3] |= shift[j & 7];
  4827.                                 else
  4828.                                     line[k][j >> 3] &= masks[j & 7];
  4829.                             }
  4830.                         }
  4831.                     }
  4832.  
  4833.                     base += raster;
  4834.  
  4835.                     for(k = 0 ; k < depth ; k++)
  4836.                         line[k] += modulo;
  4837.                 }
  4838.                 while(--h);
  4839.             }
  4840.             else
  4841.             {
  4842.                 if(one == gx_no_color_index)
  4843.                 {
  4844.                     do
  4845.                     {
  4846.                         for(i = sourcex, j = x ; i < w ; i++, j++)
  4847.                         {
  4848.                             if(base[i >> 3] & shift[i & 7])
  4849.                             {
  4850.                                 for(k = 0 ; k < depth ; k++)
  4851.                                 {
  4852.                                     if(zero & (1 << k))
  4853.                                         line[k][j >> 3] |= shift[j & 7];
  4854.                                     else
  4855.                                         line[k][j >> 3] &= masks[j & 7];
  4856.                                 }
  4857.                             }
  4858.                         }
  4859.  
  4860.                         base += raster;
  4861.  
  4862.                         for(k = 0 ; k < depth ; k++)
  4863.                             line[k] += modulo;
  4864.                     }
  4865.                     while(--h);
  4866.                 }
  4867.                 else
  4868.                 {
  4869.                     do
  4870.                     {
  4871.                         for(i = sourcex, j = x ; i < w ; i++, j++)
  4872.                         {
  4873.                             if(base[i >> 3] & shift[i & 7])
  4874.                             {
  4875.                                 for(k = 0 ; k < depth ; k++)
  4876.                                 {
  4877.                                     if(one & (1 << k))
  4878.                                         line[k][j >> 3] |= shift[j & 7];
  4879.                                     else
  4880.                                         line[k][j >> 3] &= masks[j & 7];
  4881.                                 }
  4882.                             }
  4883.                             else
  4884.                             {
  4885.                                 for(k = 0 ; k < depth ; k++)
  4886.                                 {
  4887.                                     if(zero & (1 << k))
  4888.                                         line[k][j >> 3] |= shift[j & 7];
  4889.                                     else
  4890.                                         line[k][j >> 3] &= masks[j & 7];
  4891.                                 }
  4892.                             }
  4893.                         }
  4894.  
  4895.                         base += raster;
  4896.  
  4897.                         for(k = 0 ; k < depth ; k++)
  4898.                             line[k] += modulo;
  4899.                     }
  4900.                     while(--h);
  4901.                 }
  4902.             }
  4903.         }
  4904.  
  4905.         return(0);
  4906.     }
  4907. }
  4908.  
  4909.     /* amiga_copy_color_raw_color16():
  4910.      *
  4911.      *    Copy a color image, the source data is guaranteed to consist
  4912.      *    of one word per colour.
  4913.      */
  4914.  
  4915. int
  4916. amiga_copy_color_raw_color16(gx_device *dev,const UBYTE *data,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)
  4917. {
  4918.     if(y < 0 || x < 0 || w < 0 || h < 0)
  4919.         return(0);
  4920.     else
  4921.     {
  4922.         if(w > 0 && h > 0)
  4923.         {
  4924.             PLANEPTR line[12];
  4925.             LONG i,j,k,modulo = xdev -> rport -> BitMap -> BytesPerRow,depth = xdev -> rport -> BitMap -> Depth;
  4926.             UWORD *base = (UWORD *)data;
  4927.  
  4928.             for(i = 0 ; i < depth ; i++)
  4929.                 line[i] = xdev -> rport -> BitMap -> Planes[i] + y * modulo;
  4930.  
  4931.             w += sourcex;
  4932.  
  4933.             raster /= 2;
  4934.  
  4935.             do
  4936.             {
  4937.                 for(i = sourcex, j = x ; i < w ; i++, j++)
  4938.                 {
  4939.                     for(k = 0 ; k < depth ; k++)
  4940.                     {
  4941.                         if(base[i] & (1 << k))
  4942.                             line[k][j >> 3] |= shift[j & 7];
  4943.                         else
  4944.                             line[k][j >> 3] &= masks[j & 7];
  4945.                     }
  4946.                 }
  4947.  
  4948.                 base += raster;
  4949.  
  4950.                 for(k = 0 ; k < depth ; k++)
  4951.                     line[k] += modulo;
  4952.             }
  4953.             while(--h);
  4954.         }
  4955.  
  4956.         return(0);
  4957.     }
  4958. }
  4959.  
  4960.     /* amiga_fill_rectangle_raw_color():
  4961.      *
  4962.      *    Fill a rectangular area in a bitmap.
  4963.      */
  4964.  
  4965. int
  4966. amiga_fill_rectangle_raw_color(gx_device *dev,int x,int y,int w,int h,gx_color_index color)
  4967. {
  4968.     if(x < 0 || x > xdev -> width - w || y < 0 || y > xdev -> height - h)
  4969.         return(0);
  4970.     else
  4971.     {
  4972.         if(w > 0 && h > 0 && color != gx_no_color_index)
  4973.         {
  4974.             PLANEPTR line[12];
  4975.             LONG i,j,right,mid,modulo = xdev -> rport -> BitMap -> BytesPerRow,depth = xdev -> rport -> BitMap -> Depth;
  4976.  
  4977.             for(i = 0 ; i < depth ; i++)
  4978.                 line[i] = xdev -> rport -> BitMap -> Planes[i] + y * modulo + (x >> 3);
  4979.  
  4980.             right    = x + w;
  4981.             mid    = (right >> 3) - (x >> 3);
  4982.  
  4983.             x    &= 7;
  4984.             right    &= 7;
  4985.  
  4986.             if(mid)
  4987.             {
  4988.                 UBYTE *ptr;
  4989.  
  4990.                 do
  4991.                 {
  4992.                     for(j = 0 ; j < depth ; j++)
  4993.                     {
  4994.                         ptr = line[j];
  4995.  
  4996.                         i = mid;
  4997.  
  4998.                         if(color & (1 << j))
  4999.                         {
  5000.                             *ptr++ |= 0xFF >> x;
  5001.  
  5002.                             while(--i > 0)
  5003.                                 *ptr++ = 0xFF;
  5004.  
  5005.                             *ptr |= ~(0xFF >> right);
  5006.                         }
  5007.                         else
  5008.                         {
  5009.                             *ptr++ &= ~(0xFF >> x);
  5010.  
  5011.                             while(--i > 0)
  5012.                                 *ptr++ = 0x00;
  5013.  
  5014.                             *ptr &= 0xFF >> right;
  5015.                         }
  5016.  
  5017.                         line[j] += modulo;
  5018.                     }
  5019.                 }
  5020.                 while(--h);
  5021.             }
  5022.             else
  5023.             {
  5024.                 UBYTE    one_mask    = (0xFF >> x) & ~(0xFF >> right),
  5025.                     zero_mask    = ~(0xFF >> x) | (0xFF >> right);
  5026.                 do
  5027.                 {
  5028.                     for(j = 0 ; j < depth ; j++)
  5029.                     {
  5030.                         if(color & (1 << j))
  5031.                             *line[j] |= one_mask;
  5032.                         else
  5033.                             *line[j] &= zero_mask;
  5034.  
  5035.                         line[j] += modulo;
  5036.                     }
  5037.                 }
  5038.                 while(--h);
  5039.             }
  5040.         }
  5041.  
  5042.         return(0);
  5043.     }
  5044. }
  5045.  
  5046.     /* amiga_draw_line_raw_color():
  5047.      *
  5048.      *    Draw a hair line, your basic DDA algorithm;
  5049.      *    keep your fingers crossed.
  5050.      */
  5051.  
  5052. int
  5053. amiga_draw_line_raw_color(gx_device *dev,int x,int y,int x1,int y1,gx_color_index color)
  5054. {
  5055.     if(color != gx_no_color_index && (x != x1 || y != y1))
  5056.     {
  5057.         LONG xstep,ystep,dx,dy,diff,modulo;
  5058.         UBYTE *line,*plane,pen;
  5059.         LONG last,i,orig_x = x,orig_y = y;
  5060.  
  5061.         modulo = xdev -> rport -> BitMap -> BytesPerRow;
  5062.  
  5063.         for(i = 0 ; i < xdev -> rport -> BitMap -> Depth ; i++)
  5064.         {
  5065.             plane    = xdev -> rport -> BitMap -> Planes[i];
  5066.             line    = &plane[y1 * modulo];
  5067.             last    = y1;
  5068.             pen    = line[x1 >> 3] & (x1 & 7);
  5069.             x    = orig_x;
  5070.             y    = orig_y;
  5071.  
  5072.             dx = x1 - x;
  5073.             dy = y1 - y;
  5074.  
  5075.             if(dx < 0)
  5076.             {
  5077.                 dx = -dx;
  5078.                 dy = -dy;
  5079.  
  5080.                 x = x1;
  5081.                 y = y1;
  5082.             }
  5083.  
  5084.             if(y != last)
  5085.                 line = &plane[(last = y) * modulo];
  5086.  
  5087.             if(color & (1 << i))
  5088.             {
  5089.                 line[x >> 3] |= shift[x & 7];
  5090.  
  5091.                 xstep = ystep = 0;
  5092.  
  5093.                 if(dy < 0)
  5094.                 {
  5095.                     if(dx > -dy)
  5096.                     {
  5097.                         diff = -dx / 2;
  5098.  
  5099.                         do
  5100.                         {
  5101.                             xstep++;
  5102.  
  5103.                             if(diff > 0)
  5104.                             {
  5105.                                 ystep--;
  5106.  
  5107.                                 diff = diff - dy - dx;
  5108.                             }
  5109.                             else
  5110.                                 diff -= dy;
  5111.  
  5112.                             {
  5113.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5114.  
  5115.                                 if(y1 != last)
  5116.                                     line = &plane[(last = y1) * modulo];
  5117.  
  5118.                                 line[x1 >> 3] |= shift[x1 & 7];
  5119.                             }
  5120.                         }
  5121.                         while(xstep < dx);
  5122.                     }
  5123.                     else
  5124.                     {
  5125.                         if(dx == -dy)
  5126.                             diff = 0;
  5127.                         else
  5128.                             diff = -dy / 2;
  5129.  
  5130.                         do
  5131.                         {
  5132.                             ystep--;
  5133.  
  5134.                             if(diff > 0)
  5135.                                 diff -= dx;
  5136.                             else
  5137.                             {
  5138.                                 xstep++;
  5139.  
  5140.                                 diff = diff - dy - dx;
  5141.                             }
  5142.  
  5143.                             {
  5144.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5145.  
  5146.                                 if(y1 != last)
  5147.                                     line = &plane[(last = y1) * modulo];
  5148.  
  5149.                                 line[x1 >> 3] |= shift[x1 & 7];
  5150.                             }
  5151.                         }
  5152.                         while(ystep > dy);
  5153.                     }
  5154.                 }
  5155.                 else
  5156.                 {
  5157.                     if(dx > dy)
  5158.                     {
  5159.                         diff = -dx / 2;
  5160.  
  5161.                         do
  5162.                         {
  5163.                             xstep++;
  5164.  
  5165.                             if(diff > 0)
  5166.                             {
  5167.                                 ystep++;
  5168.  
  5169.                                 diff = diff + dy - dx;
  5170.                             }
  5171.                             else
  5172.                                 diff += dy;
  5173.  
  5174.                             {
  5175.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5176.  
  5177.                                 if(y1 != last)
  5178.                                     line = &plane[(last = y1) * modulo];
  5179.  
  5180.                                 line[x1 >> 3] |= shift[x1 & 7];
  5181.                             }
  5182.                         }
  5183.                         while(xstep < dx);
  5184.                     }
  5185.                     else
  5186.                     {
  5187.                         if(dx == dy)
  5188.                             diff = 0;
  5189.                         else
  5190.                             diff = dy / 2;
  5191.  
  5192.                         do
  5193.                         {
  5194.                             ystep++;
  5195.  
  5196.                             if(diff > 0)
  5197.                                 diff -= dx;
  5198.                             else
  5199.                             {
  5200.                                 xstep++;
  5201.  
  5202.                                 diff = diff + dy - dx;
  5203.                             }
  5204.  
  5205.                             {
  5206.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5207.  
  5208.                                 if(y1 != last)
  5209.                                     line = &plane[(last = y1) * modulo];
  5210.  
  5211.                                 line[x1 >> 3] |= shift[x1 & 7];
  5212.                             }
  5213.                         }
  5214.                         while(ystep < dy);
  5215.                     }
  5216.                 }
  5217.  
  5218.                 if(!pen)
  5219.                 {
  5220.                     if(y1 != last)
  5221.                         line = &plane[(last = y1) * modulo];
  5222.  
  5223.                     line[x1 >> 3] &= masks[x1 & 7];
  5224.                 }
  5225.             }
  5226.             else
  5227.             {
  5228.                 line[x >> 3] &= masks[x & 7];
  5229.  
  5230.                 xstep = ystep = 0;
  5231.  
  5232.                 if(dy < 0)
  5233.                 {
  5234.                     if(dx > -dy)
  5235.                     {
  5236.                         diff = -dx / 2;
  5237.  
  5238.                         do
  5239.                         {
  5240.                             xstep++;
  5241.  
  5242.                             if(diff > 0)
  5243.                             {
  5244.                                 ystep--;
  5245.  
  5246.                                 diff = diff - dy - dx;
  5247.                             }
  5248.                             else
  5249.                                 diff -= dy;
  5250.  
  5251.                             {
  5252.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5253.  
  5254.                                 if(y1 != last)
  5255.                                     line = &plane[(last = y1) * modulo];
  5256.  
  5257.                                 line[x1 >> 3] &= masks[x1 & 7];
  5258.                             }
  5259.                         }
  5260.                         while(xstep < dx);
  5261.                     }
  5262.                     else
  5263.                     {
  5264.                         if(dx == -dy)
  5265.                             diff = 0;
  5266.                         else
  5267.                             diff = -dy / 2;
  5268.  
  5269.                         do
  5270.                         {
  5271.                             ystep--;
  5272.  
  5273.                             if(diff > 0)
  5274.                                 diff -= dx;
  5275.                             else
  5276.                             {
  5277.                                 xstep++;
  5278.  
  5279.                                 diff = diff - dy - dx;
  5280.                             }
  5281.  
  5282.                             {
  5283.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5284.  
  5285.                                 if(y1 != last)
  5286.                                     line = &plane[(last = y1) * modulo];
  5287.  
  5288.                                 line[x1 >> 3] &= masks[x1 & 7];
  5289.                             }
  5290.                         }
  5291.                         while(ystep > dy);
  5292.                     }
  5293.                 }
  5294.                 else
  5295.                 {
  5296.                     if(dx > dy)
  5297.                     {
  5298.                         diff = -dx / 2;
  5299.  
  5300.                         do
  5301.                         {
  5302.                             xstep++;
  5303.  
  5304.                             if(diff > 0)
  5305.                             {
  5306.                                 ystep++;
  5307.  
  5308.                                 diff = diff + dy - dx;
  5309.                             }
  5310.                             else
  5311.                                 diff += dy;
  5312.  
  5313.                             {
  5314.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5315.  
  5316.                                 if(y1 != last)
  5317.                                     line = &plane[(last = y1) * modulo];
  5318.  
  5319.                                 line[x1 >> 3] &= masks[x1 & 7];
  5320.                             }
  5321.                         }
  5322.                         while(xstep < dx);
  5323.                     }
  5324.                     else
  5325.                     {
  5326.                         if(dx == dy)
  5327.                             diff = 0;
  5328.                         else
  5329.                             diff =  dy / 2;
  5330.  
  5331.                         do
  5332.                         {
  5333.                             ystep++;
  5334.  
  5335.                             if(diff > 0)
  5336.                                 diff -= dx;
  5337.                             else
  5338.                             {
  5339.                                 xstep++;
  5340.  
  5341.                                 diff = diff + dy - dx;
  5342.                             }
  5343.  
  5344.                             {
  5345.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5346.  
  5347.                                 if(y1 != last)
  5348.                                     line = &plane[(last = y1) * modulo];
  5349.  
  5350.                                 line[x1 >> 3] &= masks[x1 & 7];
  5351.                             }
  5352.                         }
  5353.                         while(ystep < dy);
  5354.                     }
  5355.                 }
  5356.  
  5357.                 if(pen)
  5358.                 {
  5359.                     if(y1 != last)
  5360.                         line = &plane[(last = y1) * modulo];
  5361.  
  5362.                     line[x1 >> 3] |= pen;
  5363.                 }
  5364.             }
  5365.         }
  5366.     }
  5367.  
  5368.     return(0);
  5369. }
  5370.